Entwurfsmuster (Entwurfsmuster) ist eine Reihe klassifizierter und katalogisierter Zusammenfassungen von Code-Entwurfserfahrungen, die wiederholt verwendet werden und den meisten Menschen bekannt sind.
Entwurfsmuster werden in drei Typen mit insgesamt 23 Typen unterteilt:
Verfasst unter Bezugnahme auf Artikel in Hongyang, Rookie Tutorials usw. Bitte korrigieren Sie mich, wenn es einen Verstoß gibt, kontaktieren Sie mich bitte, um ihn zu löschen.
1. Entwurfsmuster Beobachtermuster (Beobachtermuster) Am Beispiel des öffentlichen Dienstes WeChat
2. Design Pattern Factory Pattern (Factory Pattern) beginnt mit dem Verkauf von Roujiamo
3. Entwurfsmuster Singleton-Entwurfsmuster (Singleton-Muster) Vollständige Analyse
4. Entwurfsmuster Strategiemuster (Strategiemuster) nehmen Rollenspiele als Hintergrund auf
5. Entwurfsmuster Adaptermuster (Adaptermuster) Nehmen Sie das Ladegerät eines Mobiltelefons als Beispiel
6. Design Pattern Command Pattern zur Verwaltung von Smart-Home-Geräten
7. Design Pattern Decorator Pattern entführt Sie zurück in die legendäre Welt
8. Designmodus, Erscheinungsmodus (Fassadenmuster) Ein-Klick-Filmmodus
9. Design Pattern Template Method Pattern zeigt den Tag eines Programmierers
10. Entwurfsmuster-Zustandsmuster (Zustandsmuster) Nehmen Sie als Beispiel einen Verkaufsautomaten
11. Design Pattern Builder Pattern (Builder Pattern) Nehmen Sie als Beispiel den Bau eines Autos und den Kauf eines Autos
12. Entwurfsmuster Prototypmuster (Prototypmuster) Nehmen Sie als Beispiel das Erhalten mehrerer Formen
13. Das Fliegengewichtsmuster des Entwurfsmusters verwendet als Beispiel das zufällige Erhalten mehrerer Formen
14. Entwurfsmuster-Proxy-Muster (Proxy-Muster) Nehmen Sie als Beispiel das Abrufen von Bildern von der Festplatte
15. Entwurfsmuster Brückenmuster (Brückenmuster) Nehmen Sie als Beispiel das Zeichnen von Kreisen in verschiedenen Farben
16. Entwurfsmuster-Kombinationsmuster (Composite Pattern) Nehmen Sie als Beispiel das Erstellen und Drucken der Mitarbeiterhierarchie
17. Entwurfsmuster-Iteratormuster (Iteratormuster) Nehmen Sie als Beispiel die Verwendung eines Iterators zum Drucken von Namen
18. Design Pattern Mediator Pattern (Mediator Pattern) Am Beispiel öffentlicher Chatrooms
19. Entwurfsmuster Memento-Muster (Memento-Muster) Nehmen Sie Memento als Beispiel
20. Entwurfsmuster Interpretermuster (Interpretermuster) Nehmen Sie als Beispiel die Erklärung eines Satzes
21. Entwurfsmuster „Chain of Responsibility Pattern“ (Chain of Responsibility Pattern) Nehmen Sie als Beispiel das Drucken von Protokollen in Android Studio
22. Entwurfsmuster Besuchermuster (Besuchermuster) Nehmen Sie als Beispiel die Anzeige der Komponenten des Computers
- Beobachter
- Fabrik
- Singleton
- Strategie
- Adapter
- Befehl
- Dekorateur
- Fassade
- Vorlagenmethode
- Zustand
- Baumeister
- Prototyp
- Fliegengewicht
- Stellvertreter
- Brücke
- Zusammengesetzt
- Iterator
- Vermittler
- Erinnerung
- Verantwortungskette
- Gast
Definiert Eins-zu-Viele-Abhängigkeiten zwischen Objekten, sodass alle seine Abhängigkeiten benachrichtigt und automatisch aktualisiert werden, wenn sich ein Objekt ändert.
Es gibt viele Stellen in JDK oder Andorid, die das Beobachtermuster implementieren, z. B. Es handelt sich um ein Paar. Die Beziehung zwischen 1 und 1 sollte als Rückruf bezeichnet werden.
Spezielle Schnittstelle: Subject.java;
/**
* 注册一个观察者
*/
public void registerObserver ( Observer observer );
/**
* 移除一个观察者
*/
public void removeObserver ( Observer observer );
/**
* 通知所有观察者
*/
public void notifyObservers ();
Implementierungsklasse des 3D-Dienstkontos: ObjectFor3D.java
@ Override
public void registerObserver ( Observer observer ) {
observers . add ( observer );
}
@ Override
public void removeObserver ( Observer observer ) {
int index = observers . indexOf ( observer );
if ( index >= 0 ) {
observers . remove ( index );
}
}
@ Override
public void notifyObservers () {
for ( Observer observer : observers ) {
observer . update ( msg );
}
}
/**
* 主题更新信息
*/
public void setMsg ( String msg ) {
this . msg = msg ;
notifyObservers ();
}
Alle Beobachter müssen diese Schnittstelle implementieren: Observer.java
public ObserverUser1 ( Subject subject ) {
subject . registerObserver ( this );
}
@ Override
public void update ( String msg ) {
Log . e ( "-----ObserverUser1 " , "得到 3D 号码:" + msg + ", 我要记下来。" );
}
Letzter Test: ObserverActivity.java
// 创建服务号
objectFor3D = new ObjectFor3D ();
// 创建两个订阅者
observerUser1 = new ObserverUser1 ( objectFor3D );
observerUser2 = new ObserverUser2 ( objectFor3D );
// 两个观察者,发送两条信息
objectFor3D . setMsg ( "201610121 的3D号为:127" );
objectFor3D . setMsg ( "20161022 的3D号为:000" );
Lassen Sie uns kurz die Familie dieses Musters auflisten:
1. Statischer Werksmodus
2. Einfacher Fabrikmodus (Roujiamo im Laden kaufen)
public RoujiaMo creatRoujiaMo ( String type ) {
RoujiaMo roujiaMo = null ;
switch ( type ) {
case "Suan" :
roujiaMo = new ZSuanRoujiaMo ();
break ;
case "La" :
roujiaMo = new ZLaRoujiaMo ();
break ;
case "Tian" :
roujiaMo = new ZTianRoujiaMo ();
break ;
default : // 默认为酸肉夹馍
roujiaMo = new ZSuanRoujiaMo ();
break ;
}
return roujiaMo ;
}
3. Factory-Methodenmodell (Eröffnung einer Filiale)
Bietet abstrakte Methoden zum Erstellen von Roujia MoStore: RoujiaMoStore.java
public abstract RoujiaMo sellRoujiaMo ( String type );
Spezifische Implementierung der abstrakten Methode: XianRoujiaMoStore.java
Der Zweig verwendet weiterhin das einfache Fabrikmodell: XianSimpleRoujiaMoFactory.java
4. Abstraktes Fabrikmuster (unter Verwendung offizieller Rohstoffe)
/**
* 准备工作
*/
public void prepare ( RoujiaMoYLFactory roujiaMoYLFactory ) {
Meet meet = roujiaMoYLFactory . creatMeet ();
YuanLiao yuanLiao = roujiaMoYLFactory . creatYuanLiao ();
Log . e ( "---RoujiaMo:" , "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:" + meet + "yuanLiao:" + yuanLiao );
}
Der Singleton-Modus dient hauptsächlich dazu, die durch die Erstellung mehrerer Instanzen verursachte Ressourcenverschwendung zu vermeiden, und mehrere Instanzen können aufgrund mehrerer Aufrufe leicht zu falschen Ergebnissen führen. Durch die Verwendung des Singleton-Modus kann sichergestellt werden, dass in der gesamten Anwendung nur eine Instanz vorhanden ist .
Definition: Es sind nur drei Schritte erforderlich, um die Einzigartigkeit eines Objekts sicherzustellen
Definition vergleichen:
Hungriger Han-Stil [verfügbar]: SingletonEHan.java
Enthält den Lazy Han-Stil [doppelte Überprüfungssperre empfohlen]: SingletonLanHan.java
private SingletonLanHan () {}
private static SingletonLanHan singletonLanHanFour ;
public static SingletonLanHan getSingletonLanHanFour () {
if ( singletonLanHanFour == null ) {
synchronized ( SingletonLanHan . class ) {
if ( singletonLanHanFour == null ) {
singletonLanHanFour = new SingletonLanHan ();
}
}
}
return singletonLanHanFour ;
}
Strategiemuster: Definiert eine Familie von Algorithmen und kapselt sie separat, um sie austauschbar zu machen. Dieses Muster ermöglicht, dass Algorithmusänderungen unabhängig von den Kunden sind, die die Algorithmen verwenden.
RoleA roleA = new RoleA ( "---A" );
roleA . setiDisplayBehavior ( new DisplayYZ ())
. setiAttackBehavior ( new AttackXL ())
. setiDefendBehavior ( new DefendTMS ())
. setiRunBehavior ( new RunJCTQ ());
roleA . display (); // 样子
roleA . attack (); // 攻击
roleA . run (); // 逃跑
roleA . defend (); // 防御
Definition: Konvertieren Sie die Schnittstelle einer Klasse in eine andere vom Client erwartete Schnittstelle. Der Adapter ermöglicht die Zusammenarbeit von Klassen mit inkompatiblen Schnittstellen. Diese Definition ist in Ordnung, da sie besagt, dass die Funktion eines Adapters darin besteht, eine Schnittstelle in eine andere Schnittstelle umzuwandeln.
Nehmen Sie das Ladegerät als Beispiel: Ladegeräte für Mobiltelefone haben im Allgemeinen eine Spannung von etwa 5 V. Die Wechselstromspannung unseres Haushalts in China beträgt 220 V, sodass zum Aufladen von Mobiltelefonen ein Adapter (Spannungsreduzierer) erforderlich ist.
Ein Mobiltelefon: Mobile.java
Das Telefon ist auf eine Schnittstelle angewiesen, die eine Spannung von 5 V liefert: V5Power.java
Was wir haben, ist 220-V-Haushalts-Wechselstrom: V220Power.java
Adapter zur Vervollständigung der Funktion der Umwandlung von 220 V in 5 V : V5PowerAdapter.java
Letzter Test: Laden Sie das Telefon auf:
Mobile mobile = new Mobile ();
V5Power v5Power = new V5PowerAdapter ( new V200Power ());
mobile . inputPower ( v5Power );
Definition: Kapseln Sie „Anfragen“ in Objekte, sodass andere Objekte mithilfe anderer Anfragen, Warteschlangen oder Protokolle parametrisiert werden können. Der Befehlsmodus unterstützt auch rückgängig zu machende Vorgänge. (Vereinfachung: Kapseln Sie die Anforderung in ein Objekt und entkoppeln Sie den Aktionsanforderer und den Aktionsausführer.)
QuickCommand quickCloseCommand = new QuickCommand ( new Command []{ new LightOffCommand ( light ), new ComputerOffCommand ( computer ), new DoorCloseCommand ( door )});
controlPanel . setCommands ( 6 , quickOpenCommand );
controlPanel . keyPressed ( 6 );
controlPanel . setCommands ( 0 , new DoorOpenCommand ( door )); // 开门
controlPanel . keyPressed ( 0 );
Dekoratormuster: Um die Funktionalität zu erweitern, bieten Dekoratoren eine flexiblere Alternative zur Integration, indem sie Objekten dynamisch Verantwortlichkeiten zuordnen.
Lassen Sie uns kurz beschreiben, wo das Dekoratormuster ins Spiel kommt. Wenn wir eine Klasse entwerfen, müssen wir dieser Klasse einige Hilfsfunktionen hinzufügen, und wir möchten den Code dieser Klasse nicht ändern spielen. Es ist Zeit. Dies spiegelt auch einen Grundsatz wider: Klassen sollten für Erweiterungen offen und für Änderungen geschlossen sein.
Anforderungen: Entwerfen Sie das Ausrüstungssystem des Spiels. Die Grundvoraussetzung besteht darin, die Angriffskraft und Beschreibung jeder Ausrüstung berechnen zu können, nachdem sie mit verschiedenen Edelsteinen eingebettet wurde:
1. Superklasse der Ausrüstung: IEquip.java
2. Implementierungsklassen jeder Ausrüstung:
3. Superklasse der Dekorationen (Dekorationen gehören auch zur Ausrüstung): IEquipDecorator.java
4. Implementierungsklasse von Dekorationen:
5. Abschlusstest: Angriffskraft berechnen und Beschreibung ansehen:
Log . e ( "---" , "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: " );
IEquip iEquip = new RedGemDecorator ( new RedGemDecorator ( new BlueGemDecorator ( new ShoeEquip ())));
Log . e ( "---" , "攻击力:" + iEquip . caculateAttack ());
Log . e ( "---" , "描述语:" + iEquip . description ());
Definition: Bereitstellung einer einheitlichen Schnittstelle für den Zugriff auf eine Gruppe von Schnittstellen im Subsystem. Das Erscheinungsbild definiert eine Schnittstelle auf hoher Ebene, um die Verwendung des Subsystems zu vereinfachen. Tatsächlich wird aus Kundenfreundlichkeit eine Gruppe von Vorgängen in einer Methode gekapselt.
Nachfrage: Ich schaue lieber Filme, also habe ich einen Projektor, einen Computer und eine Stereoanlage gekauft, die Beleuchtung im Raum gestaltet und eine Popcornmaschine gekauft. Wenn ich dann einen Film ansehen möchte, muss ich ihn mit einem Klick ansehen und mit einem Klick ausschalten .
Schalter und andere Vorgänge für jede Geräteklasse:
zB: Popcornmaschine: PopcornPopper.java
Kinoklasse: HomeTheaterFacade.java
/**
* 一键观影
*/
public void watchMovie () {
computer . on ();
light . down ();
popcornPopper . on ();
popcornPopper . makePopcorn ();
projector . on ();
projector . open ();
player . on ();
player . make3DListener ();
}
Abschließender Test: Filmwiedergabe mit einem Klick:
new HomeTheaterFacade ( computer , light , player , popcornPopper , projector ). watchMovie ();
Definition: Definiert das Grundgerüst eines Algorithmus und verschiebt einige Schritte auf Unterklassen. Die Vorlagenmethode ermöglicht es Unterklassen, die Schritte des Algorithmus neu zu definieren, ohne die Algorithmusstruktur zu ändern.
Anforderungen: Beschreiben Sie kurz: Unser Unternehmen verfügt über Programmierer, Tester, HR, Projektmanager usw. Im Folgenden wird der Vorlagenmethodenmodus verwendet, um den Arbeitsstatus des gesamten Personals aufzuzeichnen.
Drei Arten von Rollen im Vorlagenmethodenmuster
1. Konkrete Methode
2. Abstrakte Methode
3. Hook-Methode
Worker-Superklasse: Worker.java
// 具体方法
public final void workOneDay () {
Log . e ( "workOneDay" , "-----------------work start----------------" );
enterCompany ();
work ();
exitCompany ();
Log . e ( "workOneDay" , "-----------------work end----------------" );
}
// 工作 抽象方法
public abstract void work ();
// 钩子方法
public boolean isNeedPrintDate () {
return false ;
}
private void exitCompany () {
if ( isNeedPrintDate ()) {
Log . e ( "exitCompany" , "---" + new Date (). toLocaleString () + "--->" );
}
Log . e ( "exitCompany" , name + "---离开公司" );
}
Programmierer-Implementierungsklasse (Zeit kann bekannt sein): ITWorker.java
/**
* 重写父类的此方法,使可以查看离开公司时间
*/
@ Override
public boolean isNeedPrintDate () {
return true ;
}
Abschlusstest:
Sehen Sie, wie alle arbeiten:
QAWorker qaWorker = new QAWorker ( "测试人员" );
qaWorker ();
HRWorker hrWorker = new HRWorker ( "莉莉姐" );
hrWorker . workOneDay ();
...
Überprüfen Sie, wann der Programmierer das Unternehmen verlassen hat:
ITWorker itWorker = new ITWorker ( "jingbin" );
itWorker . workOneDay ();
Definition: Ermöglicht einem Objekt, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert, sodass das Objekt so aussieht, als hätte es seine Klasse geändert.
Die Definition beginnt wieder zu verschwimmen. Wenn sich der interne Zustand eines Objekts ändert, sieht es so aus, als würde ein ähnliches Objekt neu initialisiert.
Anforderungen: Nehmen Sie als Beispiel einen Verkaufsautomaten (es gibt Status wie „Münze eingeworfen“ und „Münze nicht eingeworfen“ sowie Methoden zum Einwerfen und Zurückgeben von Münzen).
Erste Implementierung des zu verbessernden Verkaufsautomaten: VendingMachine.java
Verbesserter Verkaufsautomat (formbarer): VendingMachineBetter.java
// 放钱
public void insertMoney () {
currentState . insertMoney ();
}
// 退钱
public void backMoney () {
currentState . backMoney ();
}
// 转动曲柄
public void turnCrank () {
currentState . turnCrank ();
if ( currentState == soldState || currentState == winnerState ) {
currentState . dispense (); //两种情况会出货
}
}
// 出商品
public void dispense () {
Log . e ( "VendingMachineBetter" , "---发出一件商品" );
if ( count > 0 ) {
count --;
}
}
// 设置对应状态
public void setState ( State state ) {
this . currentState = state ;
}
Statusschnittstelle: State.java
Dem Zustand entsprechende Schnittstellenimplementierungsklasse:
Verbesserter Automatentest:
// 初始化售货机,且里面有3个商品
VendingMachineBetter machineBetter = new VendingMachineBetter ( 3 );
machineBetter . insertMoney ();
machineBetter . turnCrank ();
Der Konstruktionsmodus ist der Objekterstellungsmodus. Der Konstruktionsmodus kann die interne Darstellung eines Produkts vom Produktionsprozess des Produkts trennen, sodass ein Konstruktionsprozess Produktobjekte mit unterschiedlichen internen Darstellungen erzeugen kann.
Anforderungen: Benutzer gehen in ein Autohaus, um ein Auto zu kaufen.
Analyse: Die Autowerkstatt extrahiert entsprechende Autos entsprechend den Bedürfnissen jedes Benutzers
Builder-Superklasse: Builder
public abstract class Builder {
public abstract void setPart ( String name , String type );
public abstract Product getProduct ();
}
Builder entsprechende Implementierungsklasse: ConcreteBuilder
public class ConcreteBuilder extends Builder {
private Product product = new Product ();
@ Override
public void setPart ( String name , String type ) {
product . setName ( name );
product . setType ( type );
}
@ Override
public Product getProduct () {
return product ;
}
}
Der Filialleiter holt das Auto ab:
// 店长
Director director = new Director ();
// 得到宝马汽车,内部实现提取宝马汽车的详情操作
Product product = director . getBProduct ();
// 展示汽车信息
product . showProduct ();
Prototypmuster werden verwendet, um wiederholte Objekte zu erstellen und gleichzeitig die Leistung sicherzustellen. Bei dieser Art von Entwurfsmuster handelt es sich um ein Erstellungsmuster, das eine optimale Möglichkeit zum Erstellen von Objekten bietet.
Dieses Muster implementiert eine Prototyp-Schnittstelle, die zum Erstellen eines Klons des aktuellen Objekts verwendet wird. Dieser Modus wird verwendet, wenn die Kosten für die direkte Erstellung von Objekten relativ hoch sind. Beispielsweise muss ein Objekt nach einer teuren Datenbankoperation erstellt werden. Wir können das Objekt zwischenspeichern, bei der nächsten Anfrage einen Klon davon zurückgeben und die Datenbank bei Bedarf aktualisieren, um Datenbankaufrufe zu reduzieren.
Am Beispiel des Erhaltens mehrerer Formen gibt es vier Schritte:
1. Erstellen Sie eine abstrakte Klasse, die die Cloneable-Schnittstelle implementiert. Shape (implementiert Cloneable)
public abstract class Shape implements Cloneable {
private String id ;
protected String type ;
public abstract void draw ();
public String getId () {
return id ;
}
public void setId ( String id ) {
this . id = id ;
}
@ Override
public Object clone () {
Object object = null ;
try {
object = super . clone ();
} catch ( CloneNotSupportedException e ) {
Log . e ( "--" , e . getMessage ());
}
return object ;
}
}
2. Erstellen Sie eine Entitätsklasse, die die obige abstrakte Klasse erweitert. Kreis, Rechteck, Quadrat
public class Circle extends Shape {
public Circle () {
type = "Circle" ;
}
@ Override
public void draw () {
Log . e ( "---" , "Inside Circle::draw() method." );
}
}
3. Erstellen Sie eine Klasse, um Entitätsklassen aus der Datenbank abzurufen und sie in einer Hashtable zu speichern. ShapeCache
public class ShapeCache {
private static Hashtable < String , Shape > shapeMap = new Hashtable < String , Shape >();
public static Shape getShape ( String shapeId ) {
Shape shapeCache = shapeMap . get ( shapeId );
return ( Shape ) shapeCache . clone ();
}
// 对每种形状都运行数据库查询,并创建该形状
// shapeMap.put(shapeKey, shape);
// 例如,我们要添加三种形状
public static void loadCache () {
Circle circle = new Circle ();
circle . setId ( "1" );
shapeMap . put ( circle . getId (), circle );
Rectangle rectangle = new Rectangle ();
rectangle . setId ( "2" );
shapeMap . put ( rectangle . getId (), rectangle );
Square square = new Square ();
square . setId ( "3" );
shapeMap . put ( square . getId (), square );
}
}
4. Verwenden Sie die ShapeCache-Klasse, um einen Klon der in der Hashtable gespeicherten Form zu erhalten.
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
ShapeCache . loadCache ();
Shape shapeCache1 = ShapeCache . getShape ( "1" );
Shape shapeCache2 = ShapeCache . getShape ( "2" );
Shape shapeCache3 = ShapeCache . getShape ( "3" );
Wird hauptsächlich verwendet, um die Anzahl der erstellten Objekte zu reduzieren, um die Speichernutzung zu reduzieren und die Leistung zu verbessern. Bei dieser Art von Entwurfsmuster handelt es sich um ein Strukturmuster, das eine Möglichkeit bietet, die Anzahl der Objekte zu reduzieren und so die für die Anwendung erforderliche Objektstruktur zu verbessern.
Das Flyweight-Muster versucht, vorhandene Objekte desselben Typs wiederzuverwenden oder neue Objekte zu erstellen, wenn kein passendes Objekt gefunden wird. Wir demonstrieren dieses Muster, indem wir 5 Objekte erstellen, die 20 Kreise an verschiedenen Stellen zeichnen. Da nur 5 Farben zur Verfügung stehen, wird die Farbeigenschaft verwendet, um das vorhandene Kreisobjekt zu überprüfen.
Am Beispiel des zufälligen Erhaltens mehrerer Formen gibt es vier Schritte:
1. Erstellen Sie eine Schnittstelle.
public interface Shape {
void draw ();
}
2. Erstellen Sie eine Entitätsklasse, die die Schnittstelle implementiert.
public class Circle implements Shape {
private String color ;
private int x ;
private int y ;
private int radius ;
public Circle ( String color ) {
this . color = color ;
}
public void setX ( int x ) {
this . x = x ;
}
public void setY ( int y ) {
this . y = y ;
}
public void setRadius ( int radius ) {
this . radius = radius ;
}
@ Override
public void draw () {
Log . e ( "---" , "Circle: Draw() [Color : " + color
+ ", x : " + x + ", y :" + y + ", radius :" + radius );
}
}
3. Erstellen Sie eine Fabrik, um Objekte von Entitätsklassen basierend auf gegebenen Informationen zu generieren.
public class ShapeFactory {
private static final HashMap < String , Shape > circleMap = new HashMap < String , Shape >();
public static Shape getShape ( String color ) {
Shape shape = circleMap . get ( color );
if ( shape == null ) {
shape = new Circle ( color );
circleMap . put ( color , shape );
Log . e ( "getShape" , "Creating circle of color : " + color );
}
return shape ;
}
}
4. Verwenden Sie diese Factory, um das Objekt der Entitätsklasse durch Übergabe von Farbinformationen zu erhalten.
for ( int i = 0 ; i < 20 ; i ++) {
Circle circle = ( Circle ) ShapeFactory . getShape ( getRandomColor ());
circle . setX ( getRandomX ());
circle . setY ( getRandomY ());
circle . setRadius ( 100 );
circle . draw ();
}
Eine Klasse repräsentiert die Funktionalität einer anderen Klasse. Im Proxy-Muster erstellen wir Objekte mit vorhandenen Objekten, um eine funktionale Schnittstelle zur Außenwelt bereitzustellen. Es versteht sich, dass, wenn kein solches Objekt im Speicher vorhanden ist, es erstellt wird, und wenn ja, wird das Objekt direkt zurückgegeben.
Am Beispiel des Abrufens von Bildern von der Festplatte gibt es insgesamt drei Schritte:
1. Erstellen Sie eine Schnittstelle.
public interface Image {
void display ();
}
2. Erstellen Sie eine Entitätsklasse RealImage, die die Schnittstelle implementiert. Entsprechende Proxy-Klasse: ProxyImage.
public class RealImage implements Image {
private String fileName ;
public RealImage ( String fileName ) {
this . fileName = fileName ;
loadFromDisk ( fileName );
}
private void loadFromDisk ( String fileName ) {
Log . e ( "RealImage" , "loading " + fileName );
}
@ Override
public void display () {
Log . e ( "RealImage" , "Displaying " + fileName );
}
}
public class ProxyImage implements Image {
private String fileName ;
private RealImage realImage ;
public ProxyImage ( String fileName ) {
this . fileName = fileName ;
}
@ Override
public void display () {
if ( realImage == null ) {
realImage = new RealImage ( fileName );
}
realImage . display ();
}
}
3. Wenn Sie dazu aufgefordert werden, verwenden Sie ProxyImage, um ein Objekt der RealImage-Klasse abzurufen.
Image image = new ProxyImage ( "test_10mb.png" );
// 第一次是new的,图像从磁盘加载
image . display ();
// 第二次取缓存,图像不需要从磁盘加载
image . display ();
Bridge wird verwendet, um Abstraktion und Implementierung zu entkoppeln, sodass sich beide unabhängig voneinander ändern können. Bei dieser Art von Entwurfsmuster handelt es sich um ein Strukturmuster, das Abstraktion und Implementierung entkoppelt, indem es eine Brückenstruktur zwischen beiden bereitstellt.
Am Beispiel des Zeichnens verschiedenfarbiger Kreise gliedert sich die Umsetzung in fünf Schritte:
1. Erstellen Sie eine Bridge-Implementierungsschnittstelle.
public interface DrawAPI {
void drawCircle ( int radius , int x , int y );
}
2. Erstellen Sie eine Entity-Bridge-Implementierungsklasse, die die DrawAPI-Schnittstelle implementiert. Roter Kreis, grüner Kreis
public class RedCircle implements DrawAPI {
@ Override
public void drawCircle ( int radius , int x , int y ) {
Log . e ( "---" , "Drawing Circle[ color: red, radius: "
+ radius + ", x: " + x + ", " + y + "]" );
}
}
3. Verwenden Sie die DrawAPI-Schnittstelle, um die abstrakte Klasse Shape zu erstellen.
public abstract class Shape {
protected DrawAPI drawAPI ;
protected Shape ( DrawAPI drawAPI ) {
this . drawAPI = drawAPI ;
}
public abstract void draw ();
}
4. Erstellen Sie eine Entitätsklasse, die die Shape-Schnittstelle implementiert.
public class Circle extends Shape {
private int x , y , radius ;
protected Circle ( int x , int y , int radius , DrawAPI drawAPI ) {
super ( drawAPI );
this . x = x ;
this . y = y ;
this . radius = radius ;
}
@ Override
public void draw () {
drawAPI . drawCircle ( radius , x , y );
}
}
5. Verwenden Sie die Klassen Shape und DrawAPI, um Kreise in verschiedenen Farben zu zeichnen.
// 画红圆
Circle circle = new Circle ( 10 , 10 , 100 , new RedCircle ()); s
circle . draw ();
// 画绿圆
Circle circle2 = new Circle ( 20 , 20 , 100 , new GreenCircle ());
circle2 . draw ();
Es wird auch Teil-Ganzes-Muster genannt und wird verwendet, um eine Gruppe ähnlicher Objekte als ein einzelnes Objekt zu behandeln. Der Kompositionsmodus kombiniert Objekte gemäß einer Baumstruktur, die zur Darstellung von Teil- und Gesamthierarchien verwendet wird. Bei dieser Art von Entwurfsmuster handelt es sich um ein Strukturmuster, das eine Baumstruktur aus Gruppen von Objekten erstellt.
Nehmen Sie als Beispiel das Erstellen und Drucken einer Mitarbeiterhierarchie, das Beispiel der kleinsten Einheit:
1. Erstellen Sie eine Employee-Klasse mit einer Liste von Employee-Objekten.
public class Employee {
private String name ;
// 部门
private String dept ;
// 工资
private int salary ;
// 员工 list
private List < Employee > subordinates ;
public Employee ( String name , String dept , int salary ) {
this . name = name ;
this . dept = dept ;
this . salary = salary ;
this . subordinates = new ArrayList < Employee >();
}
public void add ( Employee e ) {
subordinates . add ( e );
}
public void remove ( Employee e ) {
subordinates . remove ( e );
}
public List < Employee > getSubordinates () {
return subordinates ;
}
@ Override
public String toString () {
return "Employee{" +
"name='" + name + ''' +
", dept='" + dept + ''' +
", salary=" + salary +
", subordinates=" + subordinates +
'}' ;
}
}
2. Verwenden Sie die Employee-Klasse, um die Mitarbeiterhierarchie zu erstellen und zu drucken.
final Employee ceo = new Employee ( "John" , "CEO" , 30000 );
Employee headSales = new Employee ( "Robert" , "Head sales" , 20000 );
Employee headMarketing = new Employee ( "Michel" , "Head Marketing" , 20000 );
Employee clerk1 = new Employee ( "Laura" , "Marketing" , 10000 );
Employee clerk2 = new Employee ( "Bob" , "Marketing" , 10000 );
Employee salesExecutive1 = new Employee ( "Richard" , "Sales" , 10000 );
Employee salesExecutive2 = new Employee ( "Rob" , "Sales" , 10000 );
ceo . add ( headSales );
ceo . add ( headMarketing );
headSales . add ( salesExecutive1 );
headSales . add ( salesExecutive2 );
headMarketing . add ( clerk1 );
headMarketing . add ( clerk2 );
Log . e ( "---" , ceo . toString ());
// 打印
/*
* Employee{name='John', dept='CEO', salary=30000,
* subordinates=[Employee{name='Robert', dept='Head sales', salary=20000,
* subordinates=[
* Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]},
* Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]},
* Employee{name='Michel', dept='Head Marketing', salary=20000,
* subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]},
* Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]}
*/
Sehr häufiges Entwurfsmuster in Java- und .Net-Programmierumgebungen. Dieses Muster wird verwendet, um nacheinander auf die Elemente eines Sammlungsobjekts zuzugreifen, ohne die zugrunde liegende Darstellung des Sammlungsobjekts zu kennen. Das Iteratormuster ist ein Verhaltensmuster.
Am Beispiel der Verwendung eines Iterators zum Drucken von Namen gibt es insgesamt drei Schritte:
1. Erstellen Sie eine Schnittstelle:
public interface Iterator {
public boolean hasNext ();
public Object next ();
}
public interface Container {
public Iterator getIterator ();
}
2. Erstellen Sie eine Entitätsklasse, die die Container-Schnittstelle implementiert. Diese Klasse verfügt über eine innere Klasse NameIterator, die die Iterator-Schnittstelle implementiert.
public class NameRepository implements Container {
private String names [] = { "John" , "jingbin" , "youlookwhat" , "lookthis" };
@ Override
public Iterator getIterator () {
return new NameIterator ();
}
private class NameIterator implements Iterator {
int index ;
@ Override
public boolean hasNext () {
if ( index < names . length ) {
return true ;
}
return false ;
}
@ Override
public Object next () {
if ( hasNext ()) {
return names [ index ++];
}
return null ;
}
}
}
3. Verwenden Sie NameRepository, um den Iterator abzurufen und den Namen auszugeben.
NameRepository nameRepository = new NameRepository ();
for ( Iterator iterator = nameRepository . getIterator (); iterator . hasNext (); ) {
String name = ( String ) iterator . next ();
Log . e ( "---" , name );
/*
* /---: John
* /---: jingbin
* /---: youlookwhat
* /---: lookthis
*/
}
Wird verwendet, um die Komplexität der Kommunikation zwischen mehreren Objekten und Klassen zu reduzieren. Dieses Muster stellt eine Zwischenklasse bereit, die normalerweise die Kommunikation zwischen verschiedenen Klassen abwickelt und eine lose Kopplung unterstützt, wodurch der Code einfacher zu warten ist. Das Mediatormodell ist ein Verhaltensmodell.
Am Beispiel eines öffentlichen Chatrooms sind die Mindesteinheitenbeispielschritte:
1. Erstellen Sie eine Zwischenklasse.
public class CharRoom {
public static void showMessage ( User user , String message ) {
Log . e ( "---" , new Date (). toString ()
+ " [" + user . getName () + "] : " + message );
}
}
2. Erstellen Sie die Benutzerklasse.
public class User {
private String name ;
public User ( String name ) {
this . name = name ;
}
public String getName () {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
public void sendMessage ( String message ) {
// 使用中介类
CharRoom . showMessage ( this , message );
}
}
3. Verwenden Sie das Benutzerobjekt, um die Kommunikation zwischen ihnen anzuzeigen.
User jingbin = new User ( "jingbin" );
jingbin . sendMessage ( "Hi~ youlookwhat!" );
//---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!
User jingbin = new User ( "youlookwhat" );
jingbin . sendMessage ( "Hi~ jingbin!" );
//---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
Speichern Sie einen bestimmten Zustand eines Objekts, damit es zu einem geeigneten Zeitpunkt wiederhergestellt werden kann. Der Memomodus ist ein Verhaltensmodus.
Am Beispiel von Memo sind die Mindesteinheitenschritte:
1. Erstellen Sie die Memento-Klasse.
public class Memento {
private String state ;
public Memento ( String state ) {
this . state = state ;
}
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
}
2. Erstellen Sie die Originator-Klasse.
public class Originator {
private String state ;
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
public Memento setSateToMemento () {
return new Memento ( state );
}
public String getStateFromMemento ( Memento memento ) {
return memento . getState ();
}
}
3. Erstellen Sie die CareTaker-Klasse.
public class CareTaker {
private List < Memento > mementoList = new ArrayList < Memento >();
public void add ( Memento memento ) {
mementoList . add ( memento );
}
public Memento get ( int index ) {
return mementoList . get ( index );
}
}
4. Verwenden Sie CareTaker- und Originator-Objekte.
// 管理者
CareTaker careTaker = new CareTaker ();
Originator originator = new Originator ();
originator . setState ( "State #1" );
originator . setState ( "State #2" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #3" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #4" );
Log . e ( "---" , "Current State: " + originator . getState ());
// 得到保存的状态
String fromMemento1 = originator . getStateFromMemento ( careTaker . get ( 0 ));
Log . e ( "---" , "First Saved State: " + fromMemento1 );
String fromMemento2 = originator . getStateFromMemento ( careTaker . get ( 1 ));
Log . e ( "---" , "Second Saved State: " + fromMemento2 );
/*
* /---: Current State: State #4
* /---: First Saved State: State #2
* /---: Second Saved State: State #3
*/
Bietet eine Möglichkeit, die Grammatik oder Ausdrücke einer Sprache zu bewerten und ist ein Verhaltensmuster. Dieses Muster implementiert eine Ausdrucksschnittstelle, die einen bestimmten Kontext interpretiert. Dieser Modus wird beim SQL-Parsing, in Symbolverarbeitungs-Engines usw. verwendet.
Nehmen Sie als Beispiel die Erklärung eines Satzes, die minimalen Einheitsschritte:
1. Erstellen Sie einen Ausdrucksschnittstellenausdruck.
public interface Expression {
public boolean interpreter ( String content );
}
2. Erstellen Sie eine Entitätsklasse, die die obige Schnittstelle implementiert. TerminalExpression, OrExpression, AndExpression.
public class TerminalExpression implements Expression {
private String data ;
public TerminalExpression ( String data ) {
this . data = data ;
}
@ Override
public boolean interpreter ( String content ) {
// 是包含判断
return content . contains ( data );
}
}
public class OrExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public OrExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) || expression2 . interpreter ( content );
}
}
public class AndExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public AndExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) && expression2 . interpreter ( content );
}
}
3. Verwenden Sie die Expression-Klasse, um Regeln zu erstellen und diese zu analysieren.
/**
* 规则:jingbin 和 youlookwhat 是男性
*/
public static Expression getMaleExpression () {
TerminalExpression jingbin = new TerminalExpression ( "jingbin" );
TerminalExpression youlookwhat = new TerminalExpression ( "youlookwhat" );
return new OrExpression ( jingbin , youlookwhat );
}
/**
* 规则:Julie 是一个已婚的女性
*/
public static Expression getMarriedWomanExpression () {
TerminalExpression julie = new TerminalExpression ( "Julie" );
TerminalExpression married = new TerminalExpression ( "Married" );
return new AndExpression ( julie , married );
}
Expression maleExpression = getMaleExpression ();
// jingbin is male: true
Log . e ( "---" , "jingbin is male: " + maleExpression . interpreter ( "jingbin" ));
Expression womanExpression = getMarriedWomanExpression ();
// Julie is married woman: true
Log . e ( "---" , "Julie is married woman: " + womanExpression . interpreter ( "Married Julie" ));
Das Chain of Responsibility Pattern erstellt eine Kette von Empfängerobjekten für eine Anfrage. Dieses Muster entkoppelt den Absender und den Empfänger der Anfrage basierend auf der Art der Anfrage. Diese Art von Entwurfsmuster ist ein Verhaltensmuster. In diesem Muster enthält normalerweise jeder Empfänger einen Verweis auf einen anderen Empfänger. Wenn ein Objekt die Anfrage nicht verarbeiten kann, leitet es dieselbe Anfrage an den nächsten Empfänger weiter und so weiter.
Am Beispiel des Druckens von Protokollen in Android Studio sind die Mindesteinheitenschritte:
1. Erstellen Sie eine abstrakte Logger-Klasse AbstractLogger.
public abstract class AbstractLogger {
public static int INFO = 1 ;
public static int DEBUG = 2 ;
public static int ERROR = 3 ;
protected int level ;
// 责任链中的下一个元素
protected AbstractLogger nextLogger ;
public void setNextLogger ( AbstractLogger nextLogger ) {
this . nextLogger = nextLogger ;
}
public void logMessage ( int level , String message ) {
if ( this . level <= level ) {
write ( message );
}
// 递归效果,不断调用下一级 logMessage
if ( nextLogger != null ) {
nextLogger . logMessage ( level , message );
}
}
protected abstract void write ( String message );
}
2. Erstellen Sie eine Entitätsklasse, die die Logger-Klasse erweitert.
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Standard Console::Logger " + message );
}
}
public class FileLogger extends AbstractLogger {
public FileLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "File::Logger " + message );
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Error Console::Logger " + message );
}
}
3. Erstellen Sie verschiedene Arten von Loggern. Geben Sie ihnen unterschiedliche Fehlerstufen und legen Sie innerhalb jedes Loggers den nächsten Logger fest. Der nächste Logger in jedem Logger stellt einen Teil der Kette dar.
public static AbstractLogger getChainOfLoggers () {
ErrorLogger errorLogger = new ErrorLogger ( AbstractLogger . ERROR );
FileLogger fileLogger = new FileLogger ( AbstractLogger . DEBUG );
ConsoleLogger consoleLogger = new ConsoleLogger ( AbstractLogger . INFO );
errorLogger . setNextLogger ( fileLogger );
fileLogger . setNextLogger ( consoleLogger );
return errorLogger ;
}
AbstractLogger logger = getChainOfLoggers ();
// ---: Standard Console::Logger this is an information.
logger . logMessage ( AbstractLogger . INFO , "this is an information." );
// ---: File::Logger this is a debug level information.
// ---: Standard Console::Logger this is a debug level information.
logger . logMessage ( AbstractLogger . DEBUG , "this is a debug level information." );
// ---: Error Console::Logger this is a error level information.
// ---: File::Logger this is a error level information.
// ---: Standard Console::Logger this is a error level information.
logger . logMessage ( AbstractLogger . ERROR , "this is a error level information." );
Im Besuchermuster verwenden wir eine Besucherklasse, die den Ausführungsalgorithmus der Elementklasse ändert. Auf diese Weise kann sich der Ausführungsalgorithmus des Elements ändern, wenn sich der Besucher ändert. Diese Art von Entwurfsmuster ist ein Verhaltensmuster. Gemäß dem Schema hat das Elementobjekt ein Besucherobjekt akzeptiert, sodass das Besucherobjekt Vorgänge am Elementobjekt verarbeiten kann.
Am Beispiel der Komponenten eines Anzeigecomputers erfolgt die Implementierung hauptsächlich in fünf Schritten:
1. Definieren Sie eine Schnittstelle, die das Element darstellt.
public interface ComputerPart {
public void accept ( ComputerPartVisitor computerPartVisitor );
}
2. Erstellen Sie eine Entitätsklasse, die die obige Klasse erweitert. Tastatur, Monitor, Maus, Computer
public class Computer implements ComputerPart {
private ComputerPart [] parts ;
public Computer () {
this . parts = new ComputerPart []{ new Mouse (), new Keyboard (), new Monitor ()};
}
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
for ( ComputerPart part : parts ) {
part . accept ( computerPartVisitor );
}
computerPartVisitor . visit ( this );
}
}
public class Mouse implements ComputerPart {
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
computerPartVisitor . visit ( this );
}
}
3. Definieren Sie eine Schnittstelle, die Besucher darstellt.
public interface ComputerPartVisitor {
public void visit ( Computer computer );
public void visit ( Mouse mouse );
public void visit ( Keyboard keyboard );
public void visit ( Monitor monitor );
}
4. Erstellen Sie Entitätsbesucher, die die oben genannten Klassen implementieren.
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@ Override
public void visit ( Computer computer ) {
Log . e ( "---" , "Displaying Computer." );
}
@ Override
public void visit ( Mouse mouse ) {
Log . e ( "---" , "Displaying Mouse." );
}
@ Override
public void visit ( Keyboard keyboard ) {
Log . e ( "---" , "Displaying Keyboard." );
}
@ Override
public void visit ( Monitor monitor ) {
Log . e ( "---" , "Displaying Monitor." );
}
}
5. Verwenden Sie ComputerPartDisplayVisitor, um die Komponenten des Computers anzuzeigen.
ComputerPart computer = new Computer ();
computer . accept ( new ComputerPartDisplayVisitor ());
/*
*打印:
*---: Displaying Mouse.
*---: Displaying Keyboard.
*---: Displaying Monitor.
*---: Displaying Computer.
*/