java - 命令模式如何将发送者与接收者解耦?

标签 java design-patterns command-pattern

Command 模式有一个 IReceiver 接口(interface),方法很少,对应于每个方法都有具体的 Command 对象(使用 execute() 方法实现接口(interface) ICommand)。

我读到客户端知 Prop 体的接收者和具体的命令,通常是客户端在具体的命令对象中设置接收者对象。那为什么说它解耦了发送方和接收方呢?

当客户端已经知 Prop 体的接收者时,我觉得这不是松散耦合,而且在这种情况下,客户端可以直接调用接收者对象上的 API(方法)。

最佳答案

你可以将命令模式的工作流程想象成下面这样。

  1. Command 为所有命令声明一个接口(interface),提供一个简单的 execute() 方法,该方法要求命令的接收者执行操作。

  2. 接收方知道如何执行请求。

  3. Invoker持有命令,可以通过调用execute方法获取Command来执行请求。

  4. Client 创建 ConcreteCommands 并为命令设置一个 Receiver

  5. ConcreteCommand 定义了 Action 和接收者之间的绑定(bind)。

  6. Invoker 调用执行 ConcreteCommand 时,将在 Receiver 上运行一个或多个操作。

查看示例代码以更好地理解事物。

public class CommandDemoEx{
    public static void main(String args[]){

        // On command for TV with same invoker 
        Receiver r = new TV();
        Command onCommand = new OnCommand(r);
        Invoker invoker = new Invoker(onCommand);
        invoker.execute();

        // On command for DVDPlayer with same invoker 
        r = new DVDPlayer();
        onCommand = new OnCommand(r);
        invoker = new Invoker(onCommand);
        invoker.execute();

    }
}
interface Command {
    public void execute();
}

class Receiver {
    public void switchOn(){
        System.out.println("Switch on from:"+this.getClass().getSimpleName());
    }
}

class OnCommand implements Command{

    private Receiver receiver;

    public OnCommand(Receiver receiver){
        this.receiver = receiver;
    }
    public void execute(){
        receiver.switchOn();
    }
}

class Invoker {
    public Command command;

    public Invoker(Command c){
        this.command=c;
    }
    public void execute(){
        this.command.execute();
    }
}

class TV extends Receiver{
    public TV(){

    }
    public String toString(){
        return this.getClass().getSimpleName();
    }
}
class DVDPlayer extends Receiver{
    public DVDPlayer(){

    }
    public String toString(){
        return this.getClass().getSimpleName();
    }
}

输出:

java CommandDemoEx
Switch on from:TV
Switch on from:DVDPlayer

回答你的问题:

I have read client knows about the concrete receiver and concrete command and it is usually client setting up the receiver object in the concrete command object. Then why it is said it decouples the sender and the receiver

为了使词语标准化,将“发送者”替换为“调用者”。现在通过代码。

  1. Invoker 只需传递 ConcreteReceiver 即可执行 ConcreteCommand(在本例中为 OnCommand)。
  2. ConcreteCommand 通过 ConcreteReceiver 执行命令ConcreteCommand 定义 Action 和 Receiver 之间的绑定(bind)。
  3. 如果您看到工作流程,Invoker 不会随着其他命令而改变,您可以在 Invoker 的 execute() 方法中添加业务逻辑,例如 java.lang.Thread,如下所述。
  4. 以这种方式客户端(发送方)和接收方通过调用者松耦合,调用者知道要执行什么命令

线程示例 来自 link

您可以通过实现 Runnable 对象来创建线程。

Thread t = new Thread (new MyRunnable()).start();

=>

 Invoker invoker = new Invoker(new ConcreteCommand());
 invoker.start() 

并且您在 start() 中有调用 ConcreteCommand.execute() 的逻辑,在上述情况下为 run()。

start() 方法会调用 Thread 中的 run() 方法。如果直接直接调用run()方法会怎么样呢?它不会被视为线程

和这个线程的start()方法一样,可以在Invoker中加入一些业务逻辑。

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
            stop0(throwableFromStop);
        }
    }

private native void start0(); // Native code is not here but this method will call run() method

public void run() {
    if (target != null) {
        target.run();
    }
}

编辑:

关于你的最后一个查询

Here we are creating the command object, Receiver object and Invoker Object.Then passing the receiver object in the command object and then passing the command object in invoker object. This we do for each Receiver like we do here for TV and DVDPlayer. Also in the method 'main' Object of TV and DVDPlayer are known and in fact are created. We can simply do tvObject.switchOn() and dvdPlayer.switchOn(). How does Command pattern help

客户端不必担心 Receiver 类的变化。 Invoker 直接作用于 ConcreteCommand,它有 Receiver 对象。 Receiver 对象将来可能会将 siwtchOn() 更改为 switchOnDevice()。但客户端交互不会改变。

如果您有两个不同的命令,例如 switchOn() 和 switchOff(),您仍然可以使用相同的 Invoker

关于java - 命令模式如何将发送者与接收者解耦?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35276941/

相关文章:

java - 在同一台机器上运行 selenium grid hub 和 node

java - 在java中查找EDT时间

python循环,金字塔模式

java - 命令模式应用的真实世界示例

polymorphism - 为什么 std::visit 不能消除模板重载的歧义

java - 命令设计模式简单的 GUI 空指针

java - 如何将对象数组打印到屏幕上?

java - 解析 XML 时出错 : unbound prefix - Element type "LinearLayout" must be followed by either attribute specifications

java - 抽象基类与作为父类(super class)型的具体类

php - 试图理解 Post/Redirect/Get 设计模式(用 PHP 实现)