Beispiel für die Verwendung des Entwurfsmodus-Befehlsmodus in benutzerdefinierten Funktionstasten eines Java-Desktop-Programms

Szenen

Um eine Desktop-Version der Anwendung zu entwickeln, stellt die Anwendung Benutzern eine Reihe benutzerdefinierter Funktionstasten zur Verfügung. Benutzer können diese Funktionstasten verwenden, um einige Verknüpfungsvorgänge auszuführen.

Benutzer können Funktionstasten und entsprechende Funktionen miteinander verknüpfen und auch die Einstellung von Funktionstasten je nach Bedarf ändern. Das System fügt möglicherweise in Zukunft einige neue Funktionen oder Funktionstasten hinzu.

Dies ist möglich, wenn Sie das Befehlsmuster nicht verwenden.

Die Funktionstastenklasse FunctionButton fungiert als Absender der Anforderung und die Hilfedokumentverarbeitungsklasse HelpHandler fungiert als Empfänger der Anforderung im onClick() des Absenders FunctionButton

-Methode ruft die display()-Methode des Empfängers HelpHandler auf.

Funktionsschaltfläche:

public class FunctionButton {
    //帮助文档处理类,请求接收者
    private HelpHandler helperHandler;

    public void onClick(){
        helperHandler = new HelpHandler();
        //显示帮助文档
        helperHandler.display();
    }
}

HelpHandler:

public class HelpHandler {
    public void display(){
        System.out.println("显示帮助文档");
    }
}

Probleme mit den oben genannten:

(1) Da zwischen dem Anforderungssender und dem Anforderungsempfänger ein direkter Methodenaufruf besteht, ist der Kopplungsgrad sehr hoch und der Quellcode des Absenders muss geändert werden, um den Anforderungsempfänger zu ersetzen.

Wenn Sie den HelpHandler des Anforderungsempfängers in WindowHanlder (Fensterverarbeitungsklasse) ändern müssen, müssen Sie den Quellcode von FunctionButton ändern, was gegen das „Öffnungs- und Schließprinzip“ verstößt.

(2) Die Funktion der FunctionButton-Klasse wurde während des Entwurfs und der Implementierung behoben. Wenn ein neuer Anforderungsempfänger hinzugefügt wird und die ursprüngliche FunctionButton-Klasse nicht geändert wird,

Dann muss eine neue Klasse ähnlich FunctionButton hinzugefügt werden, was zu einem starken Anstieg der Anzahl der Klassen im System führt.

Da möglicherweise keine Beziehung zwischen den Anforderungsempfängern HelpHandler, WindowHanlder und anderen Klassen besteht, verfügen sie nicht über eine gemeinsame Abstraktionsschicht.

Daher ist es auch schwierig, FunctionButton nach dem „Abhängigkeitsinversionsprinzip“ zu entwerfen.

(3) Benutzer können die Funktion einer Funktionstaste nicht nach ihren eigenen Bedürfnissen festlegen. Sobald die Funktion einer Funktionstaste festgelegt ist, kann ihre Funktion nicht geändert werden, ohne den Quellcode zu ändern.

Dem System mangelt es an Flexibilität.

Übersicht über Befehlsmuster

In der Softwareentwicklung müssen wir häufig Anfragen an einige Objekte senden (eine oder mehrere Methoden aufrufen), wissen aber nicht, wer der Empfänger der Anfrage ist.

Ich weiß nicht, welche Operation angefordert wird. Zu diesem Zeitpunkt hoffen wir insbesondere, die Software lose gekoppelt zu gestalten, sodass der Anforderungssender und der Anforderungsempfänger vorhanden sind

Es kann die Kopplung untereinander beseitigen, die Aufrufbeziehung zwischen Objekten flexibler gestalten und den Anforderungsempfänger und die angeforderte Operation flexibel angeben.

Der Befehlsmodus bietet eine perfektere Lösung für solche Probleme.

Der Befehlsmodus kann den Absender und Empfänger der Anforderung vollständig entkoppeln. Es besteht keine direkte Referenzbeziehung zwischen Absender und Empfänger. Das Objekt, das die Anforderung sendet, muss lediglich wissen, wie die Anforderung gesendet werden soll.

ohne dass Sie wissen müssen, wie Sie die Anfrage abschließen.

Befehlsmuster:

Die Kapselung einer Anfrage als Objekt ermöglicht es uns, Clients mit unterschiedlichen Anfragen zu parametrisieren, Anfragen in die Warteschlange zu stellen oder Anfrageprotokolle aufzuzeichnen und rückgängig zu machende Vorgänge zu unterstützen.

Der Befehlsmodus ist ein Objektverhaltensmodus, sein Alias ​​ist der Aktionsmodus oder der Transaktionsmodus.

Strukturdiagramm des Befehlsmodus

Die im Befehlsmodus enthaltenen Rollen:

Befehl (abstrakte Befehlsklasse):

Bei der abstrakten Befehlsklasse handelt es sich im Allgemeinen um eine abstrakte Klasse oder Schnittstelle, in der Methoden wie Execute() zum Ausführen von Anforderungen deklariert werden.

Über diese Methoden können verwandte Vorgänge des Anforderungsempfängers aufgerufen werden.

ConcreteCommand (spezifische Befehlsklasse):

Die konkrete Befehlsklasse ist eine Unterklasse der abstrakten Befehlsklasse, die die in der abstrakten Befehlsklasse deklarierten Methoden implementiert und dem spezifischen Empfängerobjekt entspricht.

Binden Sie die Aktionen des Empfängerobjekts daran. Bei der Implementierung der Methodeexecute() wird die entsprechende Operation (Aktion) des Empfängerobjekts aufgerufen.

Invoker (Anrufer):

Der Aufrufer ist der Absender der Anfrage und führt die Anfrage über das Befehlsobjekt aus. Ein Anrufer muss seinen Empfänger nicht zur Entwurfszeit bestimmen,

Daher ist es nur der abstrakten Befehlsklasse zugeordnet. Während der Ausführung des Programms kann ein bestimmtes Befehlsobjekt in das Programm eingefügt werden.

Rufen Sie dann die Methodeexecute () des spezifischen Befehlsobjekts auf, um die zugehörigen Vorgänge des indirekten Anrufempfängers zu realisieren.

Empfänger:

Der Empfänger führt Vorgänge im Zusammenhang mit der Anfrage aus und implementiert die Geschäftsverarbeitung der Anfrage. Der Kern des Befehlsmodus besteht darin, die Anforderung zu kapseln.

Eine Anfrage entspricht einem Befehl, wodurch die Verantwortung für die Erteilung des Befehls von der Verantwortung für die Ausführung des Befehls getrennt wird. Jeder Befehl ist eine Operation:

Die anfragende Partei sendet eine Anfrage zur Durchführung einer Operation; die empfangende Partei empfängt die Anfrage und führt die entsprechende Operation aus.

Der Befehlsmodus ermöglicht es der anfordernden Partei und der empfangenden Partei, unabhängig zu sein, sodass die anfordernde Partei die Schnittstelle der empfangenden Partei nicht kennen muss.

Es ist nicht erforderlich zu wissen, wie die Anfrage empfangen wird, ob die Operation ausgeführt wird, wann sie ausgeführt wird und wie sie ausgeführt wird.

Notiz:

Blog:
Domineering Rogue Temperament_C#, Architecture Road, SpringBoot-CSDN-Blog

erreichen

Verwenden Sie den Befehlsmodus, um die oben genannten benutzerdefinierten Funktionstasten zu implementieren.

1. Erstellen Sie eine neue abstrakte Befehlsklasse

//抽象命令类
abstract class Command {
    public abstract void execute();
}

2. Erstellen Sie eine neue spezifische Befehlsklasse: Hilfebefehlsklasse

//帮助命令类:具体命令类
public class HelpCommand extends Command{

    //维持对请求接收者的引用
    private HelpHandler helpHandler;

    public HelpCommand(){
        helpHandler = new HelpHandler();
    }

    //命令执行方法,将调用请求接收者的业务方法
    public void execute() {
        helpHandler.display();
    }
}

Es behält einen Verweis auf den Empfänger der Anfrage bei.

3. Erstellen Sie einen neuen Anforderungsempfänger und helfen Sie der Dokumentverarbeitungsklasse

//帮助文档处理类:请求接受者
public class HelpHandler {
    public void display(){
        System.out.println("显示帮助文档");
    }
}

4. Erstellen Sie auf die gleiche Weise eine neue spezifische Befehlsklasse: Minimieren Sie die Befehlsklasse

//最小化命令类:具体命令类
public class MinimizeCommand extends Command{

    //维持对请求接收者的引用
    private WindowHandler windowHandler;

    public MinimizeCommand(){
        windowHandler = new WindowHandler();
    }

    //命令执行方法,将调用请求接收者的业务方法
    public void execute() {
        windowHandler.minimize();
    }
}

Dadurch wird ein Verweis auf die minimierte Fensterbehandlungsklasse des Anforderungsempfängers beibehalten

5. Erstellen Sie eine neue Verarbeitungsklasse für minimierte Fenster

//窗口处理类:请求接收者
public class WindowHandler {
    public void minimize(){
        System.out.println("将窗口最小化");
    }
}

6. Neuer Anfragesender: Funktionstastenklasse

//功能键类:请求发送者
public class FunctionButton {
    //功能键名称
    private String name;
    //维持一个抽象命令对象的引用
    private Command command;

    public FunctionButton(String name) {
        this.name = name;
    }

    public String getName(){
        return this.name;
    }

    //为功能键注入命令
    public void setCommand(Command command){
        this.command = command;
    }

    public void onClick(){
        System.out.println("点击功能键:");
        command.execute();
    }
}

7. Erstellen Sie eine neue Funktionstaste, um die Fensterklasse festzulegen

import java.util.ArrayList;

//功能键设置窗口类
public class FBSettingWindow {
    //窗口标题
    private String title;
    //定义一个ArrayList来存储所有功能键
    private ArrayList<FunctionButton> functionButtons = new ArrayList<FunctionButton>();

    public FBSettingWindow(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void addFunctionButton(FunctionButton fb){
        functionButtons.add(fb);
    }

    public void removeFunctionButton(FunctionButton fb){
        functionButtons.remove(fb);
    }

    //显示窗口及功能键
    public void display(){
        System.out.println("显示窗口:"+this.title);
        System.out.println("显示功能键:");
        for (Object obj : functionButtons) {
            System.out.println(((FunctionButton)obj).getName());
        }
        System.out.println("-------------------------");
    }
}

8. Client-Aufrufmethode

public class Client {
    public static void main(String[] args) {
        FBSettingWindow fbsw = new FBSettingWindow("功能键设置");

        FunctionButton fb1,fb2;
        fb1 = new FunctionButton("功能键1");
        fb2 = new FunctionButton("功能键2");

        Command command1,command2;
        //通过读取配置文件或其它方式生成具体命令对象
        command1 = new HelpCommand();
        command2 = new MinimizeCommand();

        //将命令对象注入功能键
        fb1.setCommand(command1);
        fb2.setCommand(command2);

        fbsw.addFunctionButton(fb1);
        fbsw.addFunctionButton(fb2);
        fbsw.display();

        //调用功能键的业务方法
        fb1.onClick();
        fb2.onClick();

    }
}

9. Zusammenfassung

Wenn Sie beispielsweise die Funktion der Funktionstaste ändern müssen, kann eine bestimmte Funktionstaste eine „automatische Bildschirmaufnahme“ realisieren. Sie müssen lediglich eine neue spezifische Befehlsklasse entsprechend hinzufügen.

Erstellen Sie eine Zuordnungsbeziehung zwischen der Befehlsklasse und dem Bildschirmhandler (ScreenHandler) und fügen Sie dann das Objekt der spezifischen Befehlsklasse über die Konfigurationsdatei in eine Funktionstaste ein.

Der Originalcode muss nicht geändert werden und entspricht dem „Open-and-Close-Prinzip“. Dabei entspricht jede spezifische Befehlsklasse einem Anforderungsprozessor (Empfänger).

Durch das Einfügen unterschiedlicher spezifischer Befehlsobjekte in den Anforderungssender kann derselbe Absender verschiedenen Empfängern entsprechen, um „eine Anforderung in ein Objekt einzukapseln“ zu realisieren.

Parametrieren Sie den Client mit unterschiedlichen Anforderungen. Der Client muss lediglich das spezifische Befehlsobjekt als Parameter in den Anforderungssender einfügen, ohne den Anforderungsempfänger direkt zu bedienen.

Die Hauptvorteile des Befehlsmusters:

(1) Reduzieren Sie den Kopplungsgrad des Systems. Da es keinen direkten Bezug zwischen Anforderer und Empfänger gibt, sind Anforderer und Empfänger vollständig entkoppelt.

Derselbe Anforderer kann verschiedenen Empfängern entsprechen, und derselbe Empfänger kann auch von verschiedenen Anforderern verwendet werden, und es besteht eine gute Unabhängigkeit zwischen beiden.

(2) Neue Befehle können einfach zum System hinzugefügt werden. Das Hinzufügen einer neuen spezifischen Befehlsklasse ist einfach, da das Hinzufügen einer neuen spezifischen Befehlsklasse keine Auswirkungen auf andere Klassen hat.

Es besteht keine Notwendigkeit, den Quellcode des Originalsystems oder sogar den Client-Klassencode zu ändern, um die Anforderungen des „Open-and-Close-Prinzips“ zu erfüllen.

(3) Es ist relativ einfach, eine Befehlswarteschlange oder einen Makrobefehl (kombinierten Befehl) zu entwerfen.

(4) Bereitstellung eines Entwurfs- und Implementierungsschemas für die angeforderten Rückgängig- und Wiederherstellungsvorgänge.

Die Hauptnachteile des Befehlsmusters sind folgende:

Die Verwendung des Befehlsmusters kann dazu führen, dass einige Systeme über zu viele konkrete Befehlsklassen verfügen. Da für jeden Aufrufvorgang an den Anforderungsempfänger eine bestimmte Befehlsklasse entworfen werden muss,

Daher kann es in einigen Systemen erforderlich sein, eine große Anzahl spezifischer Befehlsklassen bereitzustellen, was sich auf die Verwendung des Befehlsmodus auswirkt.

Anwendbare Szene

Erwägen Sie die Verwendung des Befehlsmusters, wenn:

(1) Das System muss den Anforderungsaufrufer und den Anforderungsempfänger entkoppeln, damit Anrufer und Empfänger nicht direkt interagieren. Der Anforderungsaufrufer muss weder die Existenz des Empfängers kennen, noch muss er wissen, wer der Empfänger ist.

Dem Empfänger muss es auch egal sein, wann er aufgerufen wird.

(2) Das System muss Anforderungen spezifizieren, Anforderungen in die Warteschlange stellen und Anforderungen zu unterschiedlichen Zeiten ausführen. Ein Befehlsobjekt und der ursprüngliche Aufrufer der Anfrage können unterschiedliche Lebensdauern haben.

Mit anderen Worten: Der ursprüngliche Anforderungssender ist möglicherweise nicht mehr vorhanden, das Befehlsobjekt selbst ist jedoch weiterhin aktiv und der Anforderungsempfänger kann über das Befehlsobjekt aufgerufen werden.

Anstatt sich um die Existenz des Aufrufers der Anfrage zu kümmern, kann dies durch Mechanismen wie das Anfordern von Protokolldateien implementiert werden.

(3) Das System muss die Rückgängig- und Wiederherstellungsvorgänge von Befehlen unterstützen.

(4) Das System muss eine Gruppe von Operationen kombinieren, um einen Makrobefehl zu bilden.

Ich denke du magst

Origin blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/131973694
Empfohlen
Rangfolge