Heim  >  Artikel  >  Java  >  Gängige Designmuster in Java

Gängige Designmuster in Java

高洛峰
高洛峰Original
2016-12-12 13:32:521155Durchsuche

Java-Designmuster;
Das Verständnis eines Programmierers von Java-Designmustern:
„Ich verstehe nicht“, warum etwas sehr Einfaches so kompliziert gemacht werden sollte. Später, als meine Erfahrung in der Softwareentwicklung zunahm, begann ich zu verstehen, dass die „Komplexität“, die ich sah, genau die Essenz von Designmustern war. Was ich als „Einfachheit“ verstand, war das Muster, einen Schlüssel zum Öffnen eines Schlosses zu verwenden Der Zweck bestand lediglich darin, sich auf die Lösung des aktuellen Problems zu konzentrieren. Die „Komplexität“ des Entwurfsmusters besteht darin, einen „Hauptschlüssel“ zu konstruieren, um eine Lösung zum Entriegeln aller Schlösser vorzuschlagen. Bevor ich Designmuster wirklich verstand, hatte ich „einfachen“ Code geschrieben.
Dieses „einfache“ ist nicht die Einfachheit der Funktion, sondern die Einfachheit des Designs. Einfaches Design bedeutet mangelnde Flexibilität und ist nur in diesem Projekt nützlich. Wenn es in anderen Projekten verwendet wird, nenne ich es „Müll“.

--> Um den Code wiederverwendbar zu machen, verwenden Sie bitte „Designmuster“, um Ihren Code zu entwerfen.

Viele Programmierer, die ich kenne, haben ihre Meinung geändert, nachdem sie mit Designmustern in Berührung gekommen sind Manche Leute beschreiben, dass sie sich nach dem Erlernen von Designmustern wie neugeboren fühlen und ein neues Niveau erreicht haben. Manche betrachten sogar das Verständnis von Designmustern als Kriterium für die Einstufung des Programmierniveaus.

Wir können nicht in die Musterfalle tappen und versuchen, Muster anzuwenden, um sie zu nutzen, sonst verfallen wir in den Formalismus. Wenn wir ein Muster verwenden, müssen wir auf die Absicht des Musters achten und nicht zu viel auf die Implementierungsdetails des Musters achten, da sich diese Implementierungsdetails unter bestimmten Umständen ändern können. Glauben Sie nicht stur, dass das Klassendiagramm oder der Implementierungscode in einem Designmusterbuch das Muster selbst darstellt.


Designprinzipien: (Wichtig)
1.
Logischer Code ist in separate Methoden unterteilt, wobei der Schwerpunkt auf der Kapselung liegt – einfach zu lesen und wiederzuverwenden.
Schreiben Sie nicht Hunderte Zeilen Logikcode in einer Methode. Trennen Sie jeden kleinen Logikcode und schreiben Sie ihn mit anderen Methoden, die leicht zu lesen sind und wiederholt aufgerufen werden können.
2.
Beim Schreiben von Klassen, Methoden und Funktionen sollten Sie Portabilität und Wiederverwendbarkeit berücksichtigen: Vermeiden Sie einmaligen Code!
Kann ich es von anderen ähnlichen Dingen bekommen? Ist es möglich, es in anderen Systemen zu bekommen?
3.
Verwenden Sie die Idee der Vererbung kompetent:
Finden Sie die Dinge heraus, die in der Anwendung gleich sind und nicht leicht zu ändern sind, extrahieren Sie sie in abstrakte Klassen und lassen Sie sie von Unterklassen erben.
Die Idee der Vererbung eignet sich auch dazu, die eigene Logik auf die Leistungen anderer zu stützen. ImageField erweitert beispielsweise JTextField;
Nutzen Sie die Idee von Schnittstellen geschickt:
Finden Sie die Bereiche heraus, die möglicherweise in der Anwendung geändert werden müssen, trennen Sie sie und vermischen Sie sie nicht mit Code, der dies tut muss nicht geändert werden.


Machen Sie eine sehr einfache Sache so kompliziert, einmaliger Code, ein Beispiel für die Vorteile des Entwurfsmusters: (Strategiemodus)
Beschreibung:
Eine Simulations-Entenspielanwendung, Anforderungen : Im Spiel tauchen Enten in verschiedenen Farben und Formen auf, die gleichzeitig schwimmen und quaken.

Die erste Methode: (einmaliger Code)
Schreiben Sie direkt die Klassen verschiedener Enten: MallardDuck//Wild duck, RedheadDuck//Red-headed duck. Für jeden Typ gibt es drei Methoden:
quack( ): Methode zum Aufrufen
swim(): Methode zum Schwimmen
display(): Methode zum Erscheinen

Zweite Methode: Verwenden Sie geerbte Eigenschaften, um die gemeinsamen Teile zu verbessern und Wiederholungsprogrammierung zu vermeiden .
Das heißt: Entwerfen Sie eine Enten-Superklasse (Superklasse) und lassen Sie verschiedene Enten diese Superklasse erben.
public class Duck{
public void quack(){ //Quack
System.out.println("Quack");
}
public void swim(){ //Swimming
System.out.println("Swimming");
}
public abstract void display(); /*Da das Erscheinungsbild unterschiedlich ist, lassen Sie die Unterklassen selbst entscheiden. */
}

Erben Sie einfach seine Unterklassen und implementieren Sie Ihre eigene display()-Methode.
//MallardDuck
öffentliche Klasse MallardDuck erweitert Duck{
public void display(){
System.out.println("Die Farbe der Stockente...");
}
}
//Rotkopfente
public class RedheadDuck erweitert Duck{
public void display(){
System.out.println("Die Farbe der Rotkopfente.. .");
}
}

Leider haben die Kunden jetzt neue Ansprüche gestellt und wollen, dass die Ente fliegt. Für uns OO-Programmierer könnte es nicht einfacher sein: Fügen Sie einfach einen zur Superklasse hinzu

Nur eine Methode reicht aus.
public class Duck{
public void quack(){ //Quack
System.out.println("Quack");
}
public void swim(){ //Swimming
          System.out.println(" Swimming"); */
public void fly(){
System.out.println("Fly! Duck");
}
}
Für Enten, die nicht fliegen können, ist nur eine einfache Abdeckung erforderlich.
//Disabled Duck
öffentliche Klasse DisabledDuck erweitert Duck{
public void display(){
System.out.println("Die Farbe der behinderten Ente...");
}
public void fly(){
//Überschreiben und nichts tun.
}
}
Andere fliegende Enten müssen nicht abgedeckt werden.

Auf diese Weise fliegen alle Enten, die diese Superklasse erben. Aber das Problem tauchte erneut auf und der Kunde wies darauf hin, dass einige Enten fliegen können und andere nicht.

>>>>>>Kommentare:

Für das obige Design gibt es möglicherweise einige Nachteile. Wenn die Superklasse neue Funktionen hat, müssen sich die Unterklassen ändern Wir sehen in der Entwicklung nicht gerne, dass sich eine Klasse ändert und sich auch eine andere Klasse ändert. Dies ist etwas unvereinbar mit dem OO-Design. Das hängt offensichtlich zusammen. Vererbung verwenden -> Der Kopplungsgrad ist zu hoch.


Die dritte Methode:

Verwenden Sie Schnittstellen zur Verbesserung.

Wir extrahieren die Teile, die anfällig für Änderungen sind, und kapseln sie, um mit der Zukunft zurechtzukommen Veränderungen. Obwohl die Codemenge zugenommen hat, wurde die Benutzerfreundlichkeit verbessert und der Kopplungsgrad verringert.

Wir extrahieren die Fliegenmethode und quacken in Duck.

public interface Flyable{

public void fly();
}
public interface Quackable{
public void quack();
}
Das endgültige Design von Duck wird:
public class Duck{
public void swim(){ //Swimming
System.out.println("swimming");
}
public abstract void display(); /*Weil des Aussehens Nein, lassen Sie die Unterklassen selbst entscheiden. */
}
Und MallardDuck, RedheadDuck, DisabledDuck können wie folgt geschrieben werden:
//Wild Duck
öffentliche Klasse MallardDuck erweitert Duck implementiert Flyable,Quackable{
public void display(){
System.out.println("Die Farbe der Wildente...");
}
public void fly(){
//Diese Methode implementieren
}
public void quack() {
//Diese Methode implementieren
}
}
//Red-Headed Duck
public class RedheadDuck erweitert Duck implementiert Flyable,Quackable{
public void display( ){
System .out.println("Die Farbe der rothaarigen Ente...");
}
public void fly(){
//Diese Methode implementieren
}
public void quack(){
//Diese Methode implementieren
}
}
//Disabled Duck implementiert nur Quackable (kann bellen, aber nicht fliegen)
öffentliche Klasse DisabledDuck erweitert Duck implementiert Quackable{
public void display( ){
System.out.println("Die Farbe der behinderten Ente...");
}
public void quack(){
//Implementieren Sie diese Methode
}
}

>>>>>>Kommentare:

Vorteile:

Auf diese Weise entworfen, unsere Das Programm reduziert die Kopplung zwischen ihnen.
Mängel:
Die Schnittstellen Flyable und Quackable schienen zunächst ziemlich gut zu sein und das Problem zu lösen (Flyable kann nur von Enten implementiert werden, die fliegen können), aber die Java-Schnittstelle verfügt nicht über Implementierungscode, sodass die Implementierungsschnittstelle dies nicht kann Erreichen Sie die Komplexität des Codes.

Die vierte Methode:

Zusammenfassung der oben genannten Methoden:

Vorteile der Vererbung: Gemeinsame Teile können wiederverwendet werden und doppelte Programmierung vermieden werden.


Vererbung Der Nachteil ist : hohe Kopplung. Sobald die Superklasse eine neue Methode hinzufügt, erben alle Unterklassen diese Methode. Wenn ein erheblicher Teil der Unterklassen diese Methode nicht implementiert, sind zahlreiche Änderungen erforderlich.

Bei der Vererbung können Unterklassen keine anderen Klassen erben.

Vorteile von Schnittstellen: Lösen Sie das Problem der starken Vererbungskopplung von Klassen oder Schnittstellen.

Schnittstellen sind nicht gut: Sie können Code nicht wirklich realisieren Wiederverwendung. Das folgende Strategiemuster kann zur Lösung verwendet werden.

------- ---- Strategie (Strategiemodus) --------------------

Wir haben ein Designprinzip:

Finden Sie die Dinge heraus, die in der Anwendung gleich sind und nicht einfach zu ändern sind, extrahieren Sie sie in abstrakte Klassen und lassen Sie sie von Unterklassen erben.
Finden Sie die Dinge heraus, die in der Anwendung möglicherweise benötigt werden. Behalten Sie sie bei Trennen Sie sie und vermischen Sie sie nicht mit Code, der nicht geändert werden muss. -->wichtig.

Um nun die „veränderlichen und unveränderten Teile“ zu trennen, werden wir zwei Klassensätze erstellen (völlig unabhängig von der Duck-Klasse), einen mit Bezug zu „fliegen“. und das andere

bezieht sich auf „Quacksalber“, und jede Klassengruppe wird ihre eigenen Aktionen umsetzen. Beispielsweise können wir eine Klasse haben, die „croak“ implementiert, eine andere Klasse, die „squeak“ implementiert, und eine andere Klasse, die „quiet“ implementiert.

Schreiben Sie zunächst zwei Schnittstellen. FlyBehavior (Flugverhalten) und QuackBehavior (Aufrufverhalten).

public interface FlyBehavior{

public void fly();

}

public interface QuackBehavior{
public void quack();
}
Wir definieren einige spezifische Implementierungen für FlyBehavior.
öffentliche Klasse FlyWithWings implementiert FlyBehavior{
public void fly(){
//Implementiert das Flugverhalten aller Enten mit Flügeln.
}
}

öffentliche Klasse FlyNoWay implementiert FlyBehavior{

public void fly(){

//Nichts tun, fliegt nicht

}
}
Mehrere spezifische Implementierungen von QuackBehavior.
öffentliche Klasse Quack implementiert QuackBehavior{
public void quack(){
//Implementiere die Quacksalber-Ente
}
}

öffentliche Klasse Squeak implementiert QuackBehavior{
public void quack(){
//Implementiere die quietschende Ente
}
}

public class MuteQuack implementiert QuackBehavior{
public void quack(){
/ /Do nichts, ruft nicht
}
}

Kommentar 1:
Dieses Design ermöglicht die Wiederverwendung von Flug- und Quaken-Aktionen durch andere Objekte, da diese Verhaltensweisen nichts mit Enten zu tun haben mehr. Und wenn wir einige neue

Verhaltensweisen hinzufügen, wirken sich diese weder auf die vorhandenen Verhaltensklassen noch auf die Entenklassen aus, die das Flugverhalten „verwenden“.


Schauen wir uns zum Schluss an, wie Duck gestaltet ist.

public class Duck{ --------->Deklarieren Sie in der abstrakten Klasse jede Schnittstelle und definieren Sie die jeder Schnittstelle entsprechende Methode.

FlyBehavior flyBehavior;//Interface

QuackBehavior quackBehavior; / /Interface

public Duck(){}
public abstract void display();
public void swim(){
//Schwimmverhalten implementieren
}
public void performFly( ; .quack();();
}
}

Sehen Sie, wie MallardDuck es macht.
-----> Generieren Sie durch die Konstruktionsmethode Instanzen der spezifischen Implementierungsklassen von „fly“ und „call“ und geben Sie so die spezifischen Attribute von „fly“ und „call“ an.
öffentliche Klasse MallardDuck erweitert Duck{
public MallardDuck {
flyBehavior = new FlyWithWings ();
quackBehavior = new Quack();
//Da MallardDuck Duck erbt, sind alle Instanzvariablen von flyBehavior und quackBehavior öffentlich void display (){
//Realize
}
}
Auf diese Weise können Sie gleichzeitig fliegen, bellen und Ihre eigene Farbe bekennen.

In diesem Entwurf können wir sehen, dass die Instanziierung von flyBehavior und quackBehavior in der Unterklasse geschrieben ist. Wir können auch dynamisch entscheiden.

Wir müssen Duck nur zwei Methoden hinzufügen.

Der Unterschied zwischen der Zuweisung von Werten zu Eigenschaften im Konstruktor und der Verwendung von Eigenschaftssetzern:

Zuweisung von Werten zu Eigenschaften im Konstruktor: fest, unveränderlich

Mithilfe von Attributsettern können Sie das Objekt nach der Instanziierung dynamisch ändern, was flexibler ist.

öffentliche Klasse Duck{
FlyBehavior flyBehavior;//Interface
QuackBehavior quackBehavior;//Interface
public void setFlyBehavior(FlyBehavior flyBehavior){
this.flyBehavior = flyBehavior;
--------------------- statische Factory-Methode (statische Factory) --------------------- - ---
(1)
Im Entwurfsmuster ist die Factory-Methode ebenfalls relativ einfach, wird jedoch häufig verwendet. Dieses Muster ist in EJB, RMI, COM, CORBA und Swing zu sehen
Der Schatten von
ist eines der wichtigsten Muster. An vielen Stellen werden wir Klassen mit dem Namen xxxFactory sehen (2)
Grundkonzept:

FactoryMethod ist eine Das kreative Muster definiert eine Schnittstelle zum Erstellen von Objekten, lässt jedoch Unterklassen entscheiden, welche Klasse instanziiert werden soll.

Normalerweise verwenden wir die Factory-Methode als Standardmethode zum Erstellen von Objekten. >Anwendung:
Wenn eine Klasse nicht vorhersagen kann, um welche Art von Objekt es sich handelt erstellt wird oder eine Klasse eine Unterklasse benötigt, um das zu erstellende Objekt anzugeben, müssen wir das Factory-Methodenmuster verwenden

-------------. ------------------- Singleton (Einzelfallmodus) ------ ------------------- -------

Grundkonzept:

Singleton ist ein kreatives Modell, das verwendet wird, um sicherzustellen, dass nur eine Instanz vorhanden ist und einen globalen Zugriffspunkt für den Zugriff darauf bereitstellt Stellen Sie sicher, dass es nur eine Instanz gibt. Datenbankverbindungen oder Socket-Verbindungen unterliegen manchmal bestimmten Einschränkungen und müssen gleichzeitig aufrechterhalten werden bei der Verwendung statischer Variablen;

erstellt ein Klassenobjekt, normalerweise in einem Konstruktor, oder verwendet eine Methode, um ein Klassenobjekt zu erstellen. Fügen Sie bei dieser Methode einfach das entsprechende Urteil hinzu.




Der Unterschied zwischen Singleton-Modus und Shared-Modus:

Sowohl der Singleton-Modus als auch der Shared-Modus machen Instanzen einer Klasse einzigartig.

Aber die Implementierung des Single-State-Modus ist:

Innerhalb der Klasse Das heißt, in der Konstruktormethode oder der statischen getInstace-Methode wird festgestellt, ob die Instanz vorhanden ist Es wird keine Erstellung durchgeführt.


Die Implementierung des Freigabemodus lautet:

Wenn Sie diese Instanz verwenden möchten, rufen Sie sie zuerst auf Ist leer, wird die Instanz generiert und die Instanz der Klasse in eine Hashtabelle eingefügt. Wenn der erhaltene Wert nicht leer ist, wird diese Instanz direkt verwendet.



(2)

Beispiel 1:

public class Singleton {

private static Singleton s; > public static Singleton getInstance() {

if (s == null)

s = new Singleton();

return s;

}

}

// Testklasse

class singletonTest {

public static void main(String[] args) {

Singleton s1 = Singleton.getInstance();

Singleton s2 = Singleton.getInstance();

if (s1= =s2)

System.out.println("s1 ist die gleiche Instanz mit s2");

else

System.out.println("s1 ist nicht die gleiche Instanz mit s2");
}
}

Das Ergebnis von singletonTest ist:
s1 ist die gleiche Instanz wie s2

(3)
Instanz 2:
class Singleton {
static boolean instance_flag = false; // true if 1 Instanz
public Singleton() {
if (instance_flag)
throw new SingletonException("Nur eine Instanz erlaubt");
else
instance_flag = true; // Flag für 1 Instanz setzen
}
}

----- -------------------------------- Beobachtermuster (Beobachter) ------------- --- ---------------
(1)
Grundkonzept:
Das Beobachtermuster ist ein Verhaltensmuster und seine Absicht besteht darin, ein Ein- Zu-viele-Beziehung zwischen Objekten Abhängigkeiten: Wenn sich der Status eines Objekts ändert, werden alle davon abhängigen Objekte benachrichtigt und automatisch aktualisiert.

Die Schlüsselobjekte dieses Musters sind das Ziel (Subjekt) und der Beobachter (Observer). Ein Ziel kann eine beliebige Anzahl von Beobachtern haben, die von ihm abhängen. Sobald sich der Status des Ziels ändert, werden alle Beobachter benachrichtigt. Als Reaktion auf diese Benachrichtigung fragt jeder Beobachter den Status des Ziels ab.

Anwendbare Szenarien:

Der Beobachtermodus wird zwischen Objekten verwendet, die Eins-zu-Viele-Abhängigkeiten haben. Wenn sich die abhängigen Objekte ändern, werden alle abhängigen Objekte zur Aktualisierung benachrichtigt. Daher sollte die Abhängigkeit über eine Methode zum Hinzufügen/Entfernen von Abhängigkeiten verfügen, und die hinzugefügten Abhängigkeiten können in einem Container abgelegt werden, und es sollte eine Methode vorhanden sein, um die Abhängigkeiten zur Aktualisierung zu benachrichtigen.

(2)
Ideen:
(1)
Ziel (Subjekt) und Beobachter-Schnittstelle (Beobachter) einrichten:
Ziel-(Subjekt)-Schnittstelle:
Erstellen Sie a Schnittstelle zum Registrieren von Beobachterobjekten; öffentliches Void-Attach (Observer o);
Richten Sie eine Schnittstelle zum Löschen von Beobachterobjekten ein.
Richten Sie eine Schnittstelle ein, um Benachrichtigungen zu veröffentlichen, wenn sich der Zielstatus ändert Schnittstelle; öffentliche Nichtigkeitsbenachrichtigung();

Beobachterschnittstelle:
Einrichten einer Aktualisierungsschnittstelle beim Empfang der Zielbenachrichtigung: öffentliche Nichtigkeitsaktualisierung();

(3)
Beispiel:
Der Lehrer hat eine Telefonnummer, damit er zum richtigen Zeitpunkt anrufen kann. In einer solchen Kombination ist der Lehrer ein Beobachter (Betreff), die Schüler sind es die Beobachter, die die Informationen kennen müssen. Wenn sich die Telefonnummer des Lehrers ändert, werden die Schüler benachrichtigt und der entsprechende Telefondatensatz

wird aktualisiert.

Die konkreten Beispiele lauten wie folgt:

Subject-Code:

public interface Subject{
public void attachment(Observer o);
public void detach(Observer o);
öffentliche Void-Benachrichtigung();
}

Beobachtercode:

öffentliche Schnittstelle Observer{

öffentliche Void-Aktualisierung();
}

Lehrercode

import java.util.Vector;

public class Teacher implementiert Subject{
private String phone;
private Vector Students;
public Teacher(){
phone = "";
Students = new Vector();
}
public void attachment(Observer o){
Students.add(o);
}
public void detach(Observer o){
Students. Remove(o);
}
public void Notice(){
for(int i=0;i0ab5d47bd83855228e5cd283166cb202 {
       Vector Students = new Vector();
       Teacher t = new Teacher();
       for(int i= 0 ;i491350252bcffe93910bb3e44cdd179ewichtig.  
*/
    public Item first();
    public Item next();
    public boolean isDone();

    public Item currentItem();

}

Controller类实现了Iterator接口.
package iterator;
import java.util.Vector;
public class Controller implementiert Iterator{
    private int current =0;
    Vectorchannel;
    public Controller(Vector v){

      channel = v;

    }
    public Item first(){
       current = 0;
       return (Item)channel.get(current);
{ (Item)channel.get(current);
    }
    public boolean isDone(){

       return current>=channel.size()-1;

    }
}

Television interface:
package iterator;
import java.util.Vector;
public interface Television{
    public Iterator createIterator();
}
HaierTV精结果Television电影。
Paket-Iterator;
import java.util.Vector;
öffentliche Klasse HaierTV implementiert Fernsehen{     ---下载
    privater Vektorkanal;
    öffentlicher HaierTV(){
       Kanal = new Vector();
      channel.addElement(new Item("channel 1")); --各电影,用VECTOR 电视
      channel.addElement(new Item("channel 2"));
      channel.addElement(new Item("channel 3"));
      channel.addElement(new Item("channel 4"));
      channel.addElement(new Item("channel 5"));
      channel.addElement(new Item("channel 6"));
      channel.addElement( new Item("channel 7"));
    }
    public Iterator createIterator(){
       return new Controller(channel);          -- 把设计VECTOR放到迭代器中国定核的中去
    }
}
Client Client:
package iterator;
public class Client{
    public static void main( String[] args){
       Television tv = new HaierTV();
       Iterator it =tv.createIterator();
       System.out.println(it.first().getName());
   { Schnittstelle:              
package iterator;
public class Item{
    private String name;
    public Item(String aName){
       name = aName;
    }
    public String getName( ){
       Rückgabename;
    }
}

-------------------------- -- Erscheinungsmodus (Fassade) ---------------
(1)
Der Erscheinungsmodus gehört zum Strukturmodus , Der Fassadenmodus definiert eine High-Level-Schnittstelle. Diese Schnittstelle erleichtert die Verwendung dieses Subsystems. Es wird nur für die folgenden Arbeiten verwendet:

Nachdem diese Prozesse 污泡发茶叶来 sind, handelt es sich um häufig verwendete Schritte. 80 % der 泡茶-Schritte sind alle dieses Beispiel. Sie können diese Aktionen


aneinanderreihen, um einen zu bilden Gesamtschritt. Das folgende Beispiel, MakeACuppa(), verwendet den Fassadenmodus. Es ist praktischer, wenn Sie die Methode verwenden.

ist der Darstellungsmodus, die Details darin sind ausgeblendet >public class TeaBag{... ..}

public class Water{.....}


public class FacadeCuppaMaker{

    private boolean TeaBagIsSteeped;

    public FacadeCuppaMaker( ){

       System.out .println("FacadeCuppaMaker 电影冲茶了");

    }

    public TeaCup makeACuppa(){

       TeaCup cup = new TeaCup();

       TeaBag teaBag = new TeaBag();

Wasser wasser = neues Wasser();

       cup.addFacadeTeaBag(teaBag);

       water.boilFacadeWater();

       cup.addFacadeWater(water);

       cup .steepTeaBag();

       return Tasse;

    }
}

----------------------- ----- Adaptermodell(Adapter) ---------------
(1)
Der Adaptermodus besteht darin, eine vorhandene Klasse/Schnittstelle wiederzuverwenden , konvertieren Sie sie in eine andere vom Kunden gewünschte Klasse/Schnittstelle.
(2)
So verwenden Sie Beispiele wieder: Wenn Sie die Klasse wiederverwenden möchten, fügen Sie sie in die Konstruktionsmethode der Zielklasse ein, instanziieren Sie sie dann Rufen Sie es in der entsprechenden Methode der Zielklasse auf und ändern Sie die ursprüngliche Methode
Parameter in

oder entsprechende Logik hinzufügen. Das heißt, die ursprünglichen Methoden vorhandener Klassen werden wiederverwendet.

Klasse, die wiederverwendet werden soll:
public class Adaptee{
public long getPower(long base,long exp){
long result=1;
for(int i= 0; i12f2f79ccff8c6ddf70ba583ac723aee Sie können anderen Logikcode vor oder nach dem Objekt hinzufügen, während Sie indirekt auf das Objekt zugreifen, und schließlich neue Logik generieren . Das heißt: Fügen Sie der Klassenmethode zusätzliche Logik hinzu und generieren Sie eine neue Methodenlogik:
--> eine Korrespondenz mit einer Proxy-Klasse.

-->Beide implementieren eine gemeinsame Schnittstelle oder erben dieselbe abstrakte Klasse

--> Instanziieren Sie einfach die ursprüngliche Klasse in der Proxy-Klasse und fügen Sie vor und nach der ursprünglichen Klassenmethode neue Logik hinzu.
Wie folgt:
Abstrakte Rolle:
abstract public class Subject
{
abstract public void request();
}

Echte Rolle:
public class RealSubject erweitert Subject
{

public void request()

{
System.out.println("From real subject.");
}
}

Proxy-Rolle:
public class ProxySubject erweitert Subject

{

private RealSubject realSubject; //Verwende die reale Rolle als Attribut der Proxy-Rolle

public ProxySubject()

{ realSubject =new RealSubject(); }

public void request() //Gleicher Name wie die ursprüngliche Methode

{
preRequest();

realSubject.request (); // Die Anforderungsmethode des realen Objekts wird hier ausgeführt

postRequest();

}

private void preRequest()

{
//something was Sie tun möchten, bevor Sie eine Anfrage stellen

}

private void postRequest()
{
//etwas, das Sie nach der Anfrage tun möchten
}
}

Kundenanruf :
Subject sub =new ProxySubject();
Sub.request();

(3)
Dynamische Proxy-Klasse
Die dynamische Java-Proxy-Klasse befindet sich unter Java. lang.reflect-Paket und umfasst im Allgemeinen die folgenden zwei Klassen:

1)

Interface InvocationHandler: In dieser Schnittstelle ist nur eine Methode definiert: invoke(Object obj,Method method, Object[] args)

. Bei der tatsächlichen Verwendung bezieht sich der erste Parameter obj im Allgemeinen auf die Proxy-Klasse, method auf die Proxy-Methode und args auf das Parameterarray der Methode. Diese abstrakte Methode

wird dynamisch in der Proxy-Klasse implementiert.

2)

Proxy: Diese Klasse ist eine dynamische Proxy-Klasse, die hauptsächlich den folgenden Inhalt enthält:

Statisches Objekt newProxyInstance(ClassLoader-Loader, Class[]-Schnittstellen, InvocationHandler h): Gibt die Proxy-Klasse zurück

Eine Instanz von

, die zurückgegebene Proxy-Klasse, kann als Proxy-Klasse verwendet werden.
Der sogenannte dynamische Proxy ist eine Klasse: Es handelt sich um eine zur Laufzeit generierte Klasse. Bei der Generierung müssen Sie ihr eine Reihe von Schnittstellen bereitstellen, und dann

die Klasse erklärt, dass sie diese implementiert Schnittstellen.
3)
Bei Verwendung einer dynamischen Proxy-Klasse müssen wir die InvocationHandler-Schnittstelle
public interface Subject
{
public void request();
}

Spezifische Rolle RealSubject: Wie oben;

Agentenrolle:

import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
öffentliche Klasse DynamicSubject implementiert InvocationHandler {
private Object sub;
public DynamicSubject(Object obj) {
sub = obj;
}

public Object invoke(Object Proxy, Method method, Object[] args) throws Throwable {

System.out.println("vor dem Aufruf " + method);

method.invoke(sub,args);

System.out.println("nach dem Aufruf " + method ; Die Ausführungsmethode, der Methodenparameter sub ist das eigentliche Proxy-Objekt und args sind die Parameter, die zum Ausführen der entsprechenden Operation des Proxy-Objekts erforderlich sind


. Über dynamische Proxy-Klassen können wir einige verwandte Vorgänge vor oder nach dem Aufruf ausführen.

Client:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java . lang.reflect.Method;

public class Client

{

static public void main(String[] args) throws Throwable
{
RealSubject rs = new RealSubject(); / /Geben Sie hier die Proxy-Klasse an
InvocationHandler ds = new DynamicSubject(rs); //Initialisieren Sie die Proxy-Klasse
Subject subject = (Subject) Proxy.newProxyInstance(rs.getClass().getClassLoader(),rs. getClass

().getInterfaces(),ds );
subject.request();
}

5)
Beispiel 2:
packagedynamicProxy

public interface Work {

public void startWork();
}

packagedynamicProxy;

public class JasonWork implementiert Work {
public void startWork() {
System .out.println("jason start to work...");
}
}

public interface Play {

public void startPlay();
}

öffentliche Klasse JasonPlay implementiert Play {
public void startPlay() {
System.out.println("jason start to play...");

}

}

public class Test {

public static void main(String[] args)

{
JasonWork work=new JasonWork();
InvocationHandlerdynamicProxy=new DynamicProxy(work);
Work jasonproxy=(Work)Proxy.newProxyInstance(work.getClass().getClassLoader(),

work.getClass().getInterfaces(), >

JasonPlay play=new JasonPlay();
InvocationHandlerdynamicProxy=new DynamicProxy(play);
Play jasonproxy=(Play)Proxy.newProxyInstance(play.getClass().getClassLoader(),

play.getClass().getInterfaces() ,dynamicProxy);
jasonproxy.startPlay();

}

}
===>Dynamische Proxy-Klasse, kann mit jedem Typ verwendet werden. Echte Klassen (Arbeit/Spiel), kombiniert, dynamisch Proxy.





---------- -------------- ----- Zustandsmodus (Zustand) ------------------- ------
(1)
Zustandsmodusdefinition:

Unterschiedliche Zustände, unterschiedliche Verhaltensweisen; mit anderen Worten, jeder Zustand hat entsprechende Verhaltensweisen:

Der Zustandsmodus ist in der tatsächlichen Verwendung häufiger und eignet sich für den „Zustandswechsel“. Um den Zustand zu wechseln, müssen wir darüber nachdenken, ob der Zustandsmodus übernommen werden kann.

-->

(2)

Ein Zustand besteht aus zwei Teilen: Objekt + Attribute innerhalb des Objekts (Attributschnittstelle + spezifische Eigenschaften)

Ein Objekt muss seine Eigenschaften sowie seine Setter und Getter haben und seine festlegen Anfangszustand + eine Methode zum Aufrufen des Anzeigezustands (in der der Zustand seine eigene Anzeigemethode aufruft).

Ein bestimmtes Attribut muss das Objekt enthalten Methode muss das nächste Attribut festgelegt werden, das auf dem Objekt angezeigt werden soll --> damit sich sein Attributwert ändert, wenn das Objekt das nächste Mal die Methode aufruft .

Der Unterschied zwischen Zustandsmodus und Beobachtermodus:

Der Zustandsmodus ist wie der Beobachtermodus ein Eins-zu-viele-Modus. Wenn sich jedoch im Beobachtermodus „eins“ ändert, werden auch alle „vielen“ aktualisiert.

Der Zustandsmodus betont, dass „viele“ die Zustände von „Eins“ sind und die Zustände von „Eins“ sich in einem kontinuierlichen Zyklus befinden.

So stellen Sie eine Beziehung zwischen Eins und Vielen her:

„Viele“ implementieren alle eine Schnittstelle. Daher wird in der Klasse „one“ die Schnittstelle „many“ deklariert. Wenn Sie eine Beziehung zu „one“ in „many“ herstellen möchten, müssen Sie „one“ nur direkt in der Klasse deklarieren.

(3)
Code:
public interface Color {
public void show();

}

Paketstatus;

Klasse Light
{
Farbfarbe;
öffentliche Farbe getColor() {
Rückgabefarbe;
}
öffentliche Leere setColor(Color color) {
this.color = color;
}

public Light()
{
color=new RedColor(this);
}

public void showColor()
{
color.show();
}

>

class RedColor implementiert Color
{
Light light;
public RedColor(Light light)
{
this.light=light;
}

public void show()
{
System.out .println("Die Farbe ist rot, das Auto muss anhalten!");
System.out.println("Schreiben Sie die gesamte Logik auf, die dies in diesem Zustand tun soll....");
setColor (new GreenColor(light));
}
}

class GreenColor implementiert Color
{
Light light;
public GreenColor(Light light)
{
this.light=light;
}

public void show()
{
System.out.println("Die Farbe ist grün, das Auto kann fahren!") ;
System.out.println("Schreiben Sie die gesamte Logik auf, um dies in diesem Zustand zu tun....");
light.setColor(new YellowColor(light));
}
}

class YellowColor implementiert Color
{
Light light;
public YellowColor(Light light)
{
this.light=light;
}

public void show()
{
System.out.println("Die Farbe ist gelb, das Auto sollte anhalten!");
System.out.println("Schreiben Sie die gesamte Logik auf, um dies zu tun in diesem Zustand...");
light.setColor(new RedColor(light));
}
}

public class CarLight {
public static void main( String[] args) {
Light light=new Light();

//Erster Aufruf ist rotes Licht
light.showColor();
//Rückruf ist grünes Licht
light.showColor();
//Erneut gelbes Licht aufrufen
light.showColor();
//Kontinuierlicher Aufruf, Dauerschleife >

------------------------------- - -- Fliegengewichtsmodus (Fliegengewicht) -------------------------------

(1)

Hauptsächlich verwendet Verwenden Sie beim Erstellen von Objekten die Sharing-Technologie, um den von Objekten belegten Speicher zu reduzieren. Ein Modus, der die Effizienz und Leistung des Programms verbessert, beschleunigt den Betrieb des Programms erheblich.

Das heißt, wenn in einem System mehrere identische Objekte vorhanden sind Objekte, dann müssen Sie nur eine Kopie freigeben und es ist nicht erforderlich, für jede ein Objekt zu instanziieren.


Der Werksmodus erscheint oft im Fliegengewichtsmodus. Der interne Status von Flyweight dient der gemeinsamen Nutzung, und die Flyweight-Fabrik ist für die Verwaltung eines Objektspeicherpools (Flyweight-Pool) zum Speichern interner Statusobjekte verantwortlich.

Die Schlüsselidee von Flyweight ist:

Beim Erstellen eines neuen Objekts:
Gehen Sie zuerst zur Hashtabelle, um es abzurufen--> Bestimmen Sie, ob das erhaltene Objekt leer ist--> Wenn ja, erstellen Sie dieses Objekt. Und fügen Sie es wieder in die Hashtabelle ein. --> Wenn es vorhanden ist, geben Sie das ursprüngliche

(2)

-Objekt frei: (Vergleichen Sie mit static Fabrikmodus)

public interface Car {

public void showCarName();


}

class BMWCar implementiert Car

{

public void showCarName()

{
System.out .println("this is the BMWCar .");
}
}

class FordCar implementiert Car

{

public void showCarName()
{
System .out.println("this is the FordCar .");
}
}

class CarFactory

{

public static Car car;
public static Car getCar( String name)
{
if("BMW".equals(name))
{
car = new BMWCar();
}

if("Ford".equals( name))

{
car = new FordCar();
}
return car;
}
}

class CarFlyWeightFactory
{
    public  Car car;
    private Hashtable219f70c21f651df0c8fbe73f27fa1bf8 carPool=new Hashtable219f70c21f651df0c8fbe73f27fa1bf8();
 public  Car getCar(String name)
 {
  if("BMW".equals(name))
  {
   car=carPool .get(name);
   if(car==null)
   {
    car=new BMWCar();
    carPool.put(name, car);
   }
  }
  
  if("Ford".equals(name))
  {
   car=carPool.get(name);
   if(car==null)
   {
car=new FordCar();
    carPool.put(name, car);
   }
  }
  return car;
 }
        public int getNumber(){ return carPool.getSize (); }
}


public class Test {

 public static void main(String[] args) {
  CarFlyWeightFactory carFlyWeightFactory=new CarFlyWeightFactory();
  Car carf1=carFlyWeightFactory.getCar("Ford");
  carf1.showCarName();
  Car carf2=carFlyWeightFactory.getCar("Ford");
  carf2.showCarName();
  if(carf1 ==carf2)
  {
   System.out.println("同一部车来的");
  }
  else
  {
   System.out.println("不同一部车来的");
  }
  System.out.println("车的数量是:"+carFlyWeightFactory.getNumber());
 }
}

输出:
das ist das FordCar .
das ist das FordCar .
同一部车来的

 

------------- --------- 职责链模式(Chain of Responsibility) -----------------------
(1)
Kette of Responsibility:机会处理请求.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止.
-->
要沿着链转发请求,并保证接受者为隐式的,每个链上的对象都有一致的处理请求和访问链上后继者的接口(即如下实例中,在自己方法中再调用一次相同的方法)。

(2)

public class Boy {
 
 private boolean hasCar ; // 是否有车
 private boolean hasHouse; // 是否有房
 private boolean hasResponsibility; // 是否有责任心

 public Boy() {

 }

 public Boy(boolean hasCar, boolean hasHouse, boolean hasResponsibility) {

  this.hasCar = hasCar;
  this.hasHouse = hasHouse;
  this.hasResponsibility = hasResponsibility;
 }

 public boolean isHasCar() {

  return hasCar;
 }

 public void setHasCar(boolean hasCar) {

  this.hasCar = hasCar;
 }

 public boolean isHasHouse() {

  return hasHouse;
 }

 public void setHasHouse(boolean hasHouse) {

  this.hasHouse = hasHouse;
 }

 public boolean isHasResponsibility() {

  return hasResponsibility;
 }

 public void setHasResponsibility (boolean hasResponsibility) {

  this.hasResponsibility = hasResponsibility;
 }
}

public interface Handler {

 public void handleRequest(Boy boy);
}

öffentliche Klasse HouseHandler implementiert Handler {

 
 private Handler handler;

 public HouseHandler(Handler handler) {

  this.handler = handler;

 }

 public Handler getHandler() {

 return handler;
 }

 public void setHandler(Handler handler) {

  this.handler = handler;
 }

 public void handleRequest(Boy boy) {

  if (boy.isHasHouse()) {
   System.out.println("没想到吧,我还有房子");
  } else {
 {

 private Handler handler;

 public CarHandler(Handler handler) {
  this.handler = handler;

 }

 public Handler getHandler() {

 return handler;

 }


 public void setHandler(Handler handler) {
  this.handler = handler;

 }

 public void handleRequest(Boy boy) {
  if (boy.isHasCar()) {
   System.out.println("呵呵,我有辆车");
  } else {
   System.out.println("我没有车");
   handler.handleRequest(boy);
  }
 }
}

öffentliche Klasse ResponsibilityHandler implementiert Handler {

 private Handler handler;

 public ResponsibilityHandler(Handler handler) {
  this.handler = handler;
 }

 public Handler getHandler() {
  return handler;
 } if (boy.isHasResponsibility()) {

   System.out.println("我只有一颗带Responsibility的心");

  } else {
   System.out.println("更没有责任心");
   handler.handleRequest(boy);

  }

 }
}

public class Girl {
 
 public static void main(String[] args ):用setHanlder方法
Handler handler = new CarHandler(new HouseHandler(
    new ResponsibilityHandler(null)));
  handler.handleRequest(boy);

 }

}

==>
如何实例使请求沿着链在各接受对象中传递,当没被第一个接受对象接受时,会传递给第二个对象,若被第一个对象接受了,则不传递下去:
1. 各具体的接受对象采用这样的构造方法:
public CarHandler(Handler handler) { this.handler = handler; }
2. Erweitern Sie die Funktion „handleRequest()“ um die Funktion „true“.接受,则执行false的内容,并继续调用再调用handleRequest() ist nicht verfügbar.
3的方法后, 会调用Haus的相应方法,最后再调用ResponsibilityHandler的方法.

==>前两个handler是采用了有参数的构造方法,最后一个是采用了为NULL的构造方法

- ----------------------------- 备忘录模式(Memento) ---------------- ---------------
(1)
备忘录模式属于行为型模式,其意图是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这

个状态,这样以后就可以将对象恢复到原先保存的状态.

(2)

实例如下:

有一个对象Employee个时刻的状态,

CareTaker,用来保存,拿回Memento.需要一个保存,还原状态的方法.->需要一个指针,一个容器.


Mitarbeiter模式:

Betreuer代码:



Kunde代码:

package memento;
public class Memento{
    String name;
    int age;
    public Memento(String name,int age){
       this.name = name;
       this.age = age;
    }
}


package memento;
public class Employee{
    private String name;
    private int age;
    public Employee(String aName,int aAge){
       name = aName;
       age = aAge;
    }
    public void setName(String aName){
       name = aName;
    }
    public void setAge(int aAge){
       age = aAge;
    }
    public Memento  saveMemento(){
       return new Memento(name,age);
    }
    public void restoreMemento(Memento memento){
       age = memento.age;
       name = memento.name;
    }
    public int getAge(){
       return age;
    }
    public String getName(){
       return name;
    }
}
Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn