Apprenez les modèles Flyweight et ConcurrentHashMap en Java

Je lis la troisième édition d'Essential Java pour tenter de mettre à jour mes connaissances de Java, et le modèle Flyweight apparaît. Au fait, je n'ai jamais fait ce modèle correctement, alors j'ai décidé de le comprendre et de l'essayer.

Modèle de poids mouche

Le modèle Flyweight est l'un des modèles de conception du GoF et est un modèle pour résoudre les problèmes suivants.

Définition

Je ne sais pas si c'est tout.

image.png

En regardant la séquence, cela ressemble à un modèle de mise en cache. En regardant l'élément d'historique, il semble qu'il a été utilisé dans l'éditeur de document, et si les informations de police, par exemple, l'alphabet est de 26 caractères, si une instance du caractère est créée à chaque fois, un grand nombre d'instances sera généré. Par conséquent, cela semble être un mécanisme pour créer seulement 26 instances, les mettre en cache et les renvoyer.

Échantillon sonore de frette de guitare

Faisons un échantillon et comprenons-le. Bref, c'est un cache d'usine, donc c'est facile. Le thème de cette fois est un peu la force brute, mais c'est une application qui renvoie le son de l'endroit lorsque vous entrez le numéro de corde et le numéro de frette de la guitare. Puisqu'il n'y a que 12 sons, 12 instances devraient suffire. Essayez d'utiliser Sound comme objet Flyweight dans le diagramme de modèle de conception.

Sound.java : Flyweight

package com.company;

public interface Sound {
    void Play();
}

SoundImpl : Flywieght1

package com.company;

public class SoundImpl implements Sound{
    private String note;
    public SoundImpl(String note) {
        this.note = note;
    }
    @Override
    public void Play() {
        System.out.println(note + "- ♪");
    }
    public String getNote() {
        return note;
    }
}

SoundFactory : FlywieghtFactory

package com.company;

import java.util.HashMap;

public class SoundFactory {
    private static Map<String, Sound> sounds = new HashMap<String, Sound>();
    public static Sound getSound(String note) {
        if (sounds.containsKey(note)){
            return sounds.get(note);
        } else {
            Sound sound = new SoundImpl(note);
            sounds.put(note, sound);
            return sound;
        }
    }
}

Le Main a gonflé et n'était pas cool, mais de toute façon, j'ai quelque chose qui a fonctionné. Le point simple est de donner à Factory une carte et de la mettre en cache. C'est facile.

Main.java

package com.company;

import java.util.HashMap;

public class Main {
    private static HashMap<Integer, Integer> stringMap = new HashMap<Integer, Integer>();
    private static HashMap<Integer, String> notes = new HashMap<Integer, String>();
    private static void setup() {
        stringMap.put(1, 4);
        stringMap.put(2, 11);
        stringMap.put(3, 7);
        stringMap.put(4, 2);
        stringMap.put(5, 9);
        stringMap.put(6, 4);

        notes.put(0, "C");
        notes.put(1, "C#");
        notes.put(2, "D");
        notes.put(3, "D#");
        notes.put(4, "E");
        notes.put(5, "F");
        notes.put(6, "F#");
        notes.put(7, "G");
        notes.put(8, "G#");
        notes.put(9, "A");
        notes.put(10, "A#");
        notes.put(11, "B");

    }
    public static void main(String[] args) {
        setup();
	    while(true) {
	        java.io.Console con = System.console();
	        if (con != null) {
                String input = con.readLine("string:fret:");
                if (input.contains("exit")) {
                    System.out.println("Closing ...");
                    System.exit(0);
                } else {
                    String[] stringFret = input.split(":");
                    int openNote = stringMap.get(Integer.parseInt(stringFret[0]));
                    int fret = Integer.parseInt(stringFret[1]);
                    int note = openNote + fret;
                    if (note >= 12) {
                        note = note - 12;
                    }
                    String noteString =  notes.get(new Integer(note));
                    Sound sound = SoundFactory.getSound(noteString);
                    sound.Play();
                }
            }

        }
    }

}

Que se passe-t-il avec Concurrent?

Comme la partie principale était facile, je ne suis pas très familier avec Java, j'ai donc décidé de prendre des mesures. Que dois-je faire s'il est dans un état concurrent? HashMap ne semble pas être sûr pour les threads. Si vous voulez le rendre sûr pour les threads, vous pouvez utiliser HashTable ou ConcurrentHashMap. Quelle est la différence?

HashTable et ConcurrentHashMap

En regardant ces comparaisons, il semble qu'il existe de nombreux cas où il est clairement approprié d'utiliser ConcurrentHashMap. Implémentons-le.

Mis en œuvre avec Micronaut

Cela semble facile.

Micronaut install

Dans mon environnement, la source de chocolatey a été réécrite, je vais donc la restaurer par défaut. Il peut être installé en démarrant PowerShell avec des privilèges d'administrateur.

$ choco isntall micronaut -s https://chocolatey.org/api/v2/

Generate project via template

Vous pouvez générer un projet Maven comme ceci:

$ mn create-app flyweight-server --build maven

Tout d'abord, cela fera démarrer le serveur. Le point auquel j'étais accro était que j'avais écrit du code en utilisant IntelliJ, mais le terminal JAVA_HOME n'était pas défini, et j'ai reçu le message d'erreur Causé par: java.lang.IllegalArgumentException: version cible invalide: 11. C'est sorti. À l'origine, seul le JDK Java8 était dans le chemin, donc c'est un problème, mais je me suis rappelé que les bases de Java sont de définir JAVA_HOME et de passer% JAVA_HOME% / bin dans le chemin. Sinon, maven ne fonctionnera pas correctement.

$ cd flywieght-server
$ mvn clean package
$ java -jar .\target\flyweight-server-0.1.jar

Ajouter un contrôleur

J'ajouterai le contrôleur. Micronaut semble prendre en charge diverses fonctions comme une version légère de Spring. Je voulais juste Http Server cette fois, alors je vais regarder le manuel et écrire le code. Pour statuer avec le contrôleur, il semble que vous ayez juste à écrire le contrôleur. C'est très facile.

*The HTTP Server

FlyweightController.java

package flyweight.server;

import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/flyweight")
public class FlyweightController {
    @Get(value = "/{string}/{fret}", produces = MediaType.TEXT_PLAIN)
    public String index(Integer string, Integer fret){
        return "String: " + string + " Fret: "+ fret;
    }
}

Maintenant que cela fonctionne, je comprends ce que le contrôleur veut savoir. Ensuite, modifions l'application Flyweight. Je pense que cela fonctionne multithread, alors utilisons le ConcurrentHashMap plus tôt.

Comme c'était plus court qu'avant. La méthode computeIfAbsent accepte désormais les fonctions et garantit le comportement atomique. C'est la même atmosphère que le C # ConcurrentDictionary. Donc, s'il n'existe pas, il en fera un nouveau et le retournera, sinon il retournera l'existant. Le meilleur!

SoundFactory.java

package flyweight.server;

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class SoundFactory {
    private static ConcurrentMap<String, Sound> sounds = new ConcurrentHashMap<String, Sound>();
    public static Sound getSound(String note) {
        return sounds.computeIfAbsent(note, n -> new SoundImpl(n));
    }
}

Vue d'ensemble

FlyweightController.java

package flyweight.server;

import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/flyweight")
public class FlyweightController {
    @Get(value = "/{string}/{fret}", produces = MediaType.TEXT_PLAIN)
    public String index(Integer string, Integer fret){
        Integer openNote = Constants.stringMap.get(string.intValue());
        int note = openNote.intValue() + fret.intValue();
        if (note >= 12) {
            note = note - 12;
        }
        Sound sound = SoundFactory.getSound(Constants.notes.get(note));
        return "String: " + string + " Fret: "+ fret + " Sound: " + sound.Play();
    }
}

Constants.java

package flyweight.server;

import java.util.HashMap;

public class Constants {
    static HashMap<Integer, Integer> stringMap = new HashMap<Integer, Integer>();
    static HashMap<Integer, String> notes = new HashMap<Integer, String>();
    static void setup() {
        stringMap.put(1, 4);
        stringMap.put(2, 11);
        stringMap.put(3, 7);
        stringMap.put(4, 2);
        stringMap.put(5, 9);
        stringMap.put(6, 4);

        notes.put(0, "C");
        notes.put(1, "C#");
        notes.put(2, "D");
        notes.put(3, "D#");
        notes.put(4, "E");
        notes.put(5, "F");
        notes.put(6, "F#");
        notes.put(7, "G");
        notes.put(8, "G#");
        notes.put(9, "A");
        notes.put(10, "A#");
        notes.put(11, "B");

    }
}

Sound.java

package flyweight.server;

public interface Sound {
    String Play();
}

SoundImpl.java

package flyweight.server;

public class SoundImpl implements Sound {
    private String note;

    public SoundImpl(String note) {
        this.note = note;
    }

    public String Play() {
        return this.note + "- note";
    }

    public String getNote() {
        return this.note;
    }
}

Application.java

package flyweight.server;

import io.micronaut.runtime.Micronaut;

public class Application {

    public static void main(String[] args) {
        Constants.setup();
        Micronaut.run(Application.class, args);
    }
}

Résultat d'exécution

[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing C:\Users\tsushi\Code\java\spike\micronaut\flyweight-server\target\flyweight-server-0.1.jar with C:\Users\tsushi\Code\java\spike\micronaut\flyweight-server\target\flyweight-server-0.1-shaded.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  7.444 s
[INFO] Finished at: 2020-10-26T14:16:48-07:00
[INFO] ------------------------------------------------------------------------
PS C:\Users\tsushi\Code\java\spike\micronaut\flyweight-server> java -jar .\target\flyweight-server-0.1.jar
←[36m14:17:24.022←[0;39m ←[1;30m[main]←[0;39m ←[34mINFO ←[0;39m ←[35mio.micronaut.runtime.Micronaut←[0;39m - Startup completed in 1154ms. Server Running: http://localhost:8080

image.png

Je suis content d'avoir appris à la légère le modèle «Flyweight» et le «ConcurrentHashMap» aujourd'hui.

Resource

Recommended Posts

Apprenez les modèles Flyweight et ConcurrentHashMap en Java
Exemple d'encodage et de décodage en Java
Comment apprendre JAVA en 7 jours
Classe StringBuffer et StringBuilder en Java
Comprendre equals et hashCode en Java
Bonjour tout le monde en Java et Gradle
Monde Java Dekon'nichiwa (Tsu apprend rapidement la grammaire dans Vim et Quickrun)
Différence entre final et immuable en Java
Programmer les en-têtes et pieds de page PDF en Java
La direction de Java dans "C ++ Design and Evolution"
De Java à C et de C à Java dans Android Studio
Lire et écrire des fichiers gzip en Java
Différence entre int et Integer en Java
Discrimination d'énum dans Java 7 et supérieur
Concernant les modificateurs transitoires et la sérialisation en Java
Détecter des vidéos similaires dans Java et OpenCV rev.2
Partition en Java
Différence entre next () et nextLine () dans Java Scanner
Changements dans Java 11
Janken à Java
Modèles de conception Java
Détecter des vidéos similaires dans Java et OpenCV rev.3
En savoir plus sur les collections et les membres dans routes.rb
Ajouter, lire et supprimer des commentaires Excel à l'aide de Java
Vérifier le comportement statique et public dans les méthodes Java
[Java] Comprenez en 10 minutes! Tableau associatif et HashMap
Java et JavaScript
XXE et Java
Distinguer les nombres positifs et négatifs en Java
Java ajoute et supprime les filigranes dans les documents Word
Détecter des vidéos similaires dans Java et OpenCV rev.1
Taux circonférentiel à Java
Représente le «jour suivant» et le «jour précédent» en Java / Android
Questions sur la gestion des exceptions Java throw et try-catch
Télécharger et télécharger des notes en java sur S3
Crypter / décrypter avec AES256 en PHP et Java
Générer OffsetDateTime à partir de Clock et LocalDateTime en Java
FizzBuzz en Java
Convertir JSON et YAML en Java (en utilisant Jackson et SnakeYAML)
Essayé l'API Toot et Streaming de Mastodon en Java
Écrivez ABNF en Java et transmettez l'adresse e-mail
Vectoriser et imager les données d'images numériques manuscrites MNIST avec Java
[Java] Différence entre statique final et final dans les variables membres
Apprentissage pour la première fois des expressions et opérateurs Java # 3
Classes et instances Java comprises dans la figure
Jonction Java et division des cellules de tableau dans un document Word
Ceci et cela pour éditer ini en Java. : inieditor-java
Comment convertir A en A et A en A en utilisant le produit logique et la somme en Java
Soustraire les constantes Enum des chaînes et des valeurs en Java
~ J'ai essayé d'apprendre la programmation fonctionnelle avec Java maintenant ~
Lire JSON en Java
Implémentation de l'interpréteur par Java
Application Janken en Java
Programmation par contraintes en Java
Mettez java8 dans centos7
NVL-ish guy en Java
Joindre des tableaux en Java