Ich lese die dritte Ausgabe von Essential Java, um meine Java-Kenntnisse zu aktualisieren, und das Muster "Fliegengewicht" wird angezeigt. Übrigens habe ich dieses Muster nie richtig gemacht, also habe ich beschlossen, es zu verstehen und auszuprobieren.
Das Flyweight-Muster ist eines der Entwurfsmuster von GoF und dient zur Lösung der folgenden Probleme.
Ich bin mir nicht sicher, ob das alles ist.
In der Sequenz sieht es aus wie ein Caching-Muster. Wenn Sie sich das Verlaufselement ansehen, scheint es, dass es im Dokumenteditor verwendet wurde. Wenn die Schriftinformationen, z. B. das Alphabet, 26 Zeichen umfassen und jedes Mal eine Instanz des Zeichens erstellt wird, wird eine große Anzahl von Instanzen generiert. Daher scheint es ein Mechanismus zu sein, nur 26 Instanzen zu erstellen und zwischenzuspeichern und zurückzugeben.
Lassen Sie uns ein Beispiel machen und es verstehen. Kurz gesagt, es ist ein Factory-Cache, also ist es einfach. Dieses Mal ist das Motiv ein wenig Brute Force, aber es ist eine Anwendung, die den Klang dieses Ortes zurückgibt, wenn Sie die Saitennummer und die Bundnummer der Gitarre eingeben. Da es nur 12 Sounds gibt, sollten 12 Instanzen ausreichen. Versuchen Sie, "Sound" als "Flyweight" -Objekt im Entwurfsmusterdiagramm zu verwenden.
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;
}
}
}
Der Main schwoll an und war nicht cool, aber trotzdem bekam ich etwas, das funktionierte. Der einfache Punkt ist, Factory eine Karte zu geben und sie zwischenzuspeichern. Es ist einfach.
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();
}
}
}
}
}
Da der Hauptteil einfach war, bin ich mit Java nicht sehr vertraut, deshalb habe ich beschlossen, Schritte zu unternehmen. Was soll ich tun, wenn es sich in einem gleichzeitigen Zustand befindet? HashMap
scheint nicht threadsicher zu sein. Wenn Sie Thread-sicher machen möchten, können Sie "HashTable" oder "ConcurrentHashMap" verwenden. Was ist der Unterschied?
Wenn man sich diese Vergleiche ansieht, scheint es viele Fälle zu geben, in denen es eindeutig angemessen ist, "ConcurrentHashMap" zu verwenden. Lassen Sie es uns implementieren.
Klingt einfach.
Micronaut install
In meiner Umgebung wurde die Quelle von "schokoladig" neu geschrieben, daher werde ich die Standardeinstellung wiederherstellen. Es kann installiert werden, indem PowerShell mit Administratorrechten gestartet wird.
$ choco isntall micronaut -s https://chocolatey.org/api/v2/
Generate project via template
Sie können ein Maven-Projekt wie folgt generieren:
$ mn create-app flyweight-server --build maven
Zunächst wird dadurch der Server hochgefahren. Der Punkt, auf den ich süchtig war, war, dass ich den Code mit IntelliJ geschrieben habe, aber das Terminal JAVA_HOME nicht festgelegt wurde und die Fehlermeldung "Verursacht durch: java.lang.IllegalArgumentException: ungültige Zielversion: 11" angezeigt wurde. Es kam heraus. Ursprünglich befand sich nur das Java8-JDK im Pfad, das ist also ein Problem, aber ich erinnerte mich daran, dass die Grundlagen von Java darin bestehen, JAVA_HOME festzulegen und% JAVA_HOME% / bin im Pfad zu übergeben. Andernfalls funktioniert maven nicht richtig.
$ cd flywieght-server
$ mvn clean package
$ java -jar .\target\flyweight-server-0.1.jar
Ich werde den Controller hinzufügen. Micronaut scheint verschiedene Funktionen zu unterstützen, wie beispielsweise eine leichte Version von Spring. Ich wollte diesmal nur HTTP-Server, also schaue ich mir das Handbuch an und schreibe den Code. Um mit dem Controller zu regieren, müssen Sie anscheinend nur den Controller schreiben. Es ist sehr leicht.
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;
}
}
Jetzt, wo es funktioniert, verstehe ich, was der Controller wissen möchte. Als nächstes ändern wir die Flyweight-App. Ich denke, das funktioniert in mehreren Threads. Verwenden wir also die zuvor erwähnte "ConcurrentHashMap".
Wie kürzer es war als zuvor. Die Methode "computeIfAbsent" akzeptiert jetzt Funktionen und garantiert atomares Verhalten. Dies ist die gleiche Atmosphäre wie beim C # ConcurrentDictionary. Wenn es also nicht existiert, erstellt es ein neues und gibt es zurück, andernfalls gibt es das vorhandene zurück. Das beste!
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));
}
}
Gesamtbild
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);
}
}
[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
Ich bin froh, dass ich heute das "Flyweight" -Muster und die "ConcurrentHashMap" leicht gelernt habe.
Resource
Recommended Posts