Design Mode (17) Behavioral Mode-Command Mode

Foreword

Behavioral design pattern is to describe how multiple classes or objects work together to complete a task that cannot be completed by a single object individually

The previous template method pattern is to give an operation flow skeleton, delay some specific steps to be implemented in the subclass
(what is eaten during the guest process is described by the subclass, the parent class only describes the guest process: order-"eat- Pay order)

Below is the command mode


Problems in reality

In software development systems, there is often a close coupling relationship between "method requesters" and "method implementers" (such as a class calling a method of another class, so that the operational coupling is high). This is not conducive to the expansion and maintenance of software functions.

Think about it, if it is a coupling relationship and you want to perform "undo, redo, record" and other processing on multiple behaviors, what should you do?
Is it necessary to record every operation, there will be more operations

Therefore, "how to decouple the method requester from the method implementer" becomes very important

Give a chestnut.
This is a multi-purpose remote control, not only to turn on and off the lights, but also to cancel

Insert picture description here

It can be better solved by using command mode


Command mode

Command Pattern : Encapsulate a request as an object, so that we can use different requests to parameterize customers; queue requests or record request logs, and support reversible operations.
Command mode is an object behavior mode, its alias is Action mode or Transaction mode

The mode motive of the command mode: The command mode can completely decouple the sender and the 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 knowing how to complete the request.

Command mode structure:

Insert picture description here

Mode role:

  • Command: abstract command class, declaring the interface for executing commands
  • ConcreteCommand: a concrete command class, an implementation of an abstract command class, which has a receiver object, and completes the operation to be performed by the command by calling the receiver's function
  • Invoker: The requester, the sender of the request, usually has many command objects (which can be stored in a collection), and executes the related request by accessing the command object, it does not directly access the receiver
  • Receiver: Receiver: the real executor of the business, execute specific commands

Command mode case

Simulate the remote control through the command mode, and control the light switch through the remote control buttons
Insert picture description here

package com.company.Behavioral.Command;

import java.util.ArrayList;
import java.util.List;

//动作执行对象
class LightReceiver{
    public void on(){
        System.out.println("电灯打开了。。。");
    }
    public void off(){
        System.out.println("电灯关闭了。。。");
    }
}
//抽象命令
interface Command {
    //执行动作
    public void execute();
    //撤销动作
    public void undo();
}
//具体命令对象:开灯命令对象
class LightOnCommend implements Command{
    //聚合LightReceiver
    private LightReceiver lightReceiver;

    public LightOnCommend(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    //当前是开灯命令,执行动作是开灯
    @Override
    public void execute() {
        lightReceiver.on();
    }
    //当前是开灯命令,撤销动作是关灯
    @Override
    public void undo() {
        lightReceiver.off();
    }
}
//具体命令对象:关灯命令对象
class LightOffCommend implements Command{
    //聚合LightReceiver
    private LightReceiver lightReceiver;

    public LightOffCommend(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    //当前是关灯命令,执行动作是关灯
    @Override
    public void execute() {
        lightReceiver.off();
    }
    //当前是关灯命令,撤销动作是关开灯
    @Override
    public void undo() {
        lightReceiver.on();
    }
}
//空命令对象:空执行,用于初始化每个按钮
//空对象模式,可以省掉对空的判断
class NoCommend implements Command{

    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}
//遥控器
class RemoteController{
    //存储命令
    private List<Command> onCommands ;
    private List<Command> offCommands ;
    //用于撤销的命令,需要记录执行命令
    private Command undoCommand;
    //构造器,初始化
    public RemoteController() {
        onCommands = new ArrayList<>();
        offCommands =  new ArrayList<>();
        //按照遥控器的按钮数,进行初始化,直接加入空命令即可
        for (int i=0;i<2;i++){
            onCommands.add(i,new NoCommend());
            offCommands.add(i,new NoCommend());
        }
    }
    //给按钮设置需要的命令
    public void setCommand(int no,Command onCommand,Command offCommand){
        onCommands.add(no,onCommand);
        offCommands.add(no,offCommand);
    }
    //如果按下开按钮
    public void onButtonPush(int no){
        //找到按下的按钮,执行该按钮的执行方法
        onCommands.get(no).execute();
        //记录这次操作,用于撤销
        undoCommand = onCommands.get(no);
    }
    //如果按下关按钮
    public void offButtonPush(int no){
        //找到按下的按钮,执行该按钮的执行方法
        offCommands.get(no).execute();
        //记录这次操作,用于撤销
        undoCommand = offCommands.get(no);
    }
    //如果按下撤销按钮
    public void undoButtonPush(int no){
        //找到按下的按钮,执行该按钮的执行方法
        undoCommand.undo();
    }
}
//客户
class Client{
    public static void main(String[] args) {
        //使用命令模式,通过遥控器,控制灯

        //创建电灯对象(真正的操作执行者)
        LightReceiver lightReceiver = new LightReceiver();

        //创建电灯的开关命令
        LightOnCommend lightOnCommend = new LightOnCommend(lightReceiver);
        LightOffCommend lightOffCommend = new LightOffCommend(lightReceiver);
        //遥控器
        RemoteController remoteController = new RemoteController();
        //给遥控器设置相关命令
        //no = 0 是电灯的开关操作
        remoteController.setCommand(0,lightOnCommend,lightOffCommend);
        //no = 1 是电视的开关操作(还未实现)

        //按灯的按钮
        System.out.println("--------按下灯的开按钮-----------");
        remoteController.onButtonPush(0);
        System.out.println("--------按下灯的关按钮-----------");
        remoteController.offButtonPush(0);
        System.out.println("---------按下撤销按钮------------");
        remoteController.undoButtonPush(0);

    }
}

The above remote controller is realized through the command mode, each remote control button is assigned a command object, and each press of the button will call the execution operation in the command object, and it is recorded and can be used to cancel the operation


Pattern analysis

The command mode realizes the complete decoupling of the requester and the executor, but the price paid is the class explosion in the system

  • The essence of the command mode is to encapsulate the command and separate the responsibility for issuing the command from the responsibility for executing the command.
  • Each command is an operation: the requesting party sends a request to perform an operation; the receiving party receives the request and performs the operation.
  • Command mode allows the requesting party and the receiving party to be independent, so that the requesting party does not need to know the interface of the receiving party, nor how the request is received, and whether the operation is performed, when it is performed, and how Executed
  • The command mode makes the request itself an object, which can be stored and transferred just like other objects.
  • The key of the command mode is that the abstract command interface is introduced, and the sender is programming for the abstract command interface. Only the specific commands that implement the abstract command interface can be associated with the receiver

For the above case, the execution process of the command mode: we can use a sequence diagram to represent
Insert picture description here


The advantages and disadvantages of the command mode

advantage

  • Reduce the coupling of the system and completely decouple the command requester and executor
  • New commands can be easily added to the system . If you want to add a TV control, you need to set up a TV control executor and two specific switch command classes
  • It is relatively easy to design a command queue and macro commands (combined commands) , after all, by maintaining a collection (ArrayList) to store command objects in the remote control (requester), you only need to design a queue
  • Undo and Redo can be easily implemented for the request , because the command is an object, which can conveniently store records

Disadvantages

Fatal shortcomings: the use of command mode will cause some systems have too many specific command classes, class explosion

In the simple case of the previous design, a command interface, two specific command classes, a command executor, a command requester, and a client are used
(simply terrible, so many types ...)

If you want to add a TV switch, you need to add a command executor and two specific command classes

Although the degree of coupling is low, it pays the cost of system resource consumption


Applicable scene

  • The system needs to decouple the requester and the executor so that the executor and the requester do not directly interact
  • The system needs to specify the request, queue the request and execute the request at different times
  • The system needs to support command undo (Undo) operation and redo (Redo) operation
  • The system needs to group a set of operations together , ie support macro commands

Obviously, the choice whether to use the command mode, see you on system resources, programming complexity and coupling choices

Real use

  1. The Java language uses the command mode to implement the delegation event model (DEM) of the AWT / Swing GUI
  2. Spring Framework JdbcTemplate application
  3. Many systems provide macro command functions, such as Shell programming under the UNIX platform, which can encapsulate multiple commands in a command object, and only need a simple command to execute a command sequence

Macro commands

In fact, we should all have been in touch with macro commands: such as mouse macros, etc.

The macro command contains a set of commands, which act as the dual role of the specific command and the caller. When executing it, all commands contained in it will be called recursively.

This is the use of command mode and combination mode

Have you noticed that we used two ArrayLists when we used the request caller, one for saving the on command onCommend and one for saving the command OffCommend

If the request caller itself is a command (implementing the Commend interface), its execution method is set to execute the execution of each command in the ArrayList, is this not the container object in our combined mode?

(It also feels a bit of the idea of ​​appearance mode, but the main focus is on the decoupling between "whole and part" and executor and requester.)
It is not clear that the combination mode can be seen: design mode (12) structural mode-combination mode

Macro commands are also called combined commands, and its structure diagram:
Insert picture description here
The execution method in CompositeCommand execute is the execute method of foreach loop calling the commands in ArrayList


to sum up

  • Command mode: encapsulate the request into an object, we can use different request objects to parameterize the client, queue the request or record the request log, and support reversible operations
  • The command mode has four roles: abstract command class, specific command class, command executor, command requester
  • The abstract command class (interface) specifies the methods that should be in the command
  • The specific command class implements the abstract commander, aggregates the executor, and implements the method of the abstract command class (actually executed by the executor)
  • Executor: the operation of executing the command, the specific business executor
  • Command requester: The sender of the request, executes the request through the command object (decoupled from the executor)
  • Command mode advantages : the command requester and the executor are coupled, with strong extensibility, macro commands can be designed, and the withdrawal operation can be easily achieved
  • Disadvantages of the command mode : the system will have too many specific command classes
  • The command mode is suitable for: need to decouple the command requester and the command executor so that the requester and the executor do not directly interact; need to specify the request at different times, queue the request and execute the request; need to support the undo operation and recovery of the command Operation; need to group a group of operations together, ie support macro commands
  • Macro commands are the combined use of command mode and combined mode, which enables command requesters to also implement abstract command classes (which are also commands), maintain some collection storage command objects, and its execution method is to call the execution method of the command objects in the collection
Published 121 original articles · won 31 · views 7869

Guess you like

Origin blog.csdn.net/key_768/article/details/105413644