Design mode-command mode usage example in Java-desktop program custom function keys

Scenes

To develop a desktop version of the application, the application provides users with a series of custom function keys, users can use these function keys to achieve some shortcut operations.

Users can bind function keys and corresponding functions together, and can also modify the setting of function keys according to needs, and the system may add some new functions or function keys in the future.

This is possible if you don't use the Command pattern.

The function key class FunctionButton acts as the sender of the request, and the help document processing class HelpHandler acts as the receiver of the request, in the onClick() of the sender FunctionButton

method will call the receiver HelpHandler's display() method.

FunctionButton:

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

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

HelpHandler:

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

Problems with the above:

(1) Since there is a direct method call between the request sender and the request receiver, the coupling degree is very high, and the source code of the sender must be modified to replace the request receiver.

If you need to change the request receiver HelpHandler to WindowHanlder (window handling class), you need to modify the source code of FunctionButton, which violates the "opening and closing principle".

(2) The function of the FunctionButton class has been fixed during design and implementation. If a new request receiver is added, if the original FunctionButton class is not modified,

Then a new class similar to FunctionButton must be added, which will lead to a sharp increase in the number of classes in the system.

Since there may not be any relationship between the request receiver HelpHandler, WindowHanlder and other classes, they do not have a common abstraction layer,

Therefore, it is also difficult to design FunctionButton according to the "dependency inversion principle".

(3) Users cannot set the function of a function key according to their own needs. Once the function of a function key is fixed, its function cannot be changed without modifying the source code.

The system lacks flexibility.

Command pattern overview

In software development, we often need to send requests to some objects (call one or some methods), but we don't know who the recipient of the request is.

I don't know which operation is requested. At this time, we especially hope to design software in a loosely coupled way, so that the request sender and request receiver

It can eliminate the coupling between each other, make the call relationship between objects more flexible, and flexibly specify the request receiver and the requested operation.

The command mode provides a more perfect solution to such problems.

The command mode can completely decouple the request sender and receiver. There is no direct reference relationship between the sender and the receiver. The object sending the request only needs to know how to send the request.

without having to know how to complete the request.

Command Pattern:

Encapsulating a request as an object allows us to parameterize clients with different requests; queue requests or record request logs, and support undoable operations.

Command mode is an object behavior mode, its alias is action (Action) mode or transaction (Transaction) mode.

Command mode structure diagram

The roles included in the command mode:

Command (abstract command class):

The abstract command class is generally an abstract class or interface, in which methods such as execute() for executing requests are declared,

Through these methods, related operations of the request receiver can be invoked.

ConcreteCommand (specific command class):

The concrete command class is a subclass of the abstract command class, which implements the methods declared in the abstract command class, and it corresponds to the specific receiver object.

Bind the actions of the receiver object to it. When implementing the execute() method, the relevant operation (Action) of the receiver object will be called.

Invoker (caller):

The caller is the sender of the request, and it executes the request through the command object. A caller does not need to determine its receiver at design time,

Therefore it is only associated with the abstract command class. A specific command object can be injected into the program when it is running,

Then call the execute() method of the specific command object, so as to realize the related operations of the indirect call receiver.

Receiver:

The receiver performs operations related to the request, and it implements the business processing of the request. The essence of the command mode is to encapsulate the request,

A request corresponds to a command, separating the responsibility for issuing the command from the responsibility for executing the command. Every command is an operation:

The requesting party sends a request to perform an operation; the receiving party receives the request and performs the corresponding operation.

The command mode allows the requesting party and the receiving party to be independent, so that the requesting party does not have to know the interface of the receiving party,

It is not necessary to know how the request is received, whether the operation is performed, when it is performed, and how it is performed.

Note:

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

accomplish

Use the command mode to implement the above user-defined function keys.

1. Create a new abstract command class

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

2. Create a new specific command class: help command class

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

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

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

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

It maintains a reference to the recipient of the request.

3. Create a new request receiver and help document processing class

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

4. Create a new specific command class in the same way: minimize the command class

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

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

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

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

Which maintains a reference to the request receiver's minimized window handling class

5. Create a new minimized window processing class

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

6. New request sender: function key class

//功能键类:请求发送者
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. Create a new function key to set the window class

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 calling method

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. Summary

If you need to modify the function of the function key, for example, a certain function key can realize "automatic screen capture", you only need to add a new specific command class correspondingly,

Create an association relationship between the command class and the screen handler (ScreenHandler), and then inject the object of the specific command class into a function key through the configuration file.

The original code does not need to be modified and complies with the "open and close principle". In this process, each specific command class corresponds to a request processor (receiver),

By injecting different specific command objects into the request sender, the same sender can correspond to different receivers, so as to realize "encapsulating a request into an object,

Parameterize the client with different requests", the client only needs to inject the specific command object as a parameter into the request sender, without directly operating the request receiver.

The main advantages of the command pattern:

(1) Reduce the coupling degree of the system. Since there is no direct reference between the requester and the receiver, the requester and receiver are completely decoupled,

The same requester can correspond to different receivers, and the same receiver can also be used by different requesters, and there is good independence between the two.

(2) New commands can be easily added to the system. Adding a new specific command class is easy because adding a new specific command class will not affect other classes,

There is no need to modify the source code of the original system, or even the client class code, to meet the requirements of the "open and close principle".

(3) It is relatively easy to design a command queue or macro command (combined command).

(4) Provide a design and implementation scheme for the requested Undo and Redo operations.

The main disadvantages of the Command pattern are as follows:

Using the command pattern may result in some systems having too many concrete command classes. Because a specific command class needs to be designed for each call operation to the request receiver,

Therefore, in some systems, it may be necessary to provide a large number of specific command classes, which will affect the use of command mode.

Applicable scene

Consider using the command pattern when:

(1) The system needs to decouple the request caller and request receiver so that the caller and receiver do not interact directly. The request caller does not need to know the existence of the receiver, nor does it need to know who the receiver is,

The receiver also doesn't have to care when it is called.

(2) The system needs to specify requests, queue requests, and execute requests at different times. A command object and the original caller of the request can have different lifetimes,

In other words, the original request sender may no longer exist, but the command object itself is still active, and the request receiver can be called through the command object,

Instead of caring about the existence of the caller of the request, it can be implemented through mechanisms such as requesting log files.

(3) The system needs to support the Undo and Redo operations of commands.

(4) The system needs to combine a group of operations to form a macro command.

Guess you like

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