当前位置: 首页 > 面试题库 >

命令模式如何使发送者与接收者脱钩?

东方权
2023-03-14
问题内容

Command模式具有一个IReceiver接口,该接口带有很少的方法,并且与每个方法相对应的都是具体的Command对象(ICommand使用execute()方法实现接口)。

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

当客户端已经知道具体的接收方时,我认为这并不是松散的耦合,并且在这种情况下,客户端也可以直接在接收方对象上调用API(方法)。


问题答案:

您可以想到以下命令模式工作流程

  1. Command 声明所有命令的接口,并提供一个简单的execute()方法,该方法要求命令Receiver进行操作。

  2. Receiver有怎样做才能执行请求的知识。

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

  4. Client创建ConcreteCommands并设置Receiver该命令。

  5. ConcreteCommand限定的动作和所述接收器之间的结合。

  6. Invoker调用执行ConcreteCommand将运行在接收一个或多个动作。

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

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

要回答您的问题:

我已经阅读了客户对具体接收方和具体命令的了解,通常是客户在具体命令对象中设置接收方对象。那为什么说它使发送者和接收者分离

为了使单词标准化,请用“ invoker”替换“ sender”。现在查看代码。

  1. Invoker simply executes the ConcreteCommand (在这种情况下为OnCommand)通过传递ConcreteReceiver。
  2. ConcreteCommand executes Command 通过ConcreteReceiver即 ConcreteCommand defines binding between Action and Receiver.
  3. 如果看到工作流程,Invoker不会更改其他命令,并且可以在execute()Invoker方法中添加业务逻辑,例如java.lang.Thread,如下所述。
  4. 就这样 Client (sender) and Receiver are loosely couple through Invoker, which has knowledge of what command to be executed

__
链接中的


线程示例

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

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

=>

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

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

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();
    }
}

编辑:

关于您的最后一个查询

在这里我们创建命令对象,接收者对象和调用者对象,然后在命令对象中传递接收者对象,然后在调用者对象中传递命令对象。就像我们在这里为电视和DVDPlayer所做的那样,我们为每个接收器执行此操作。同样在方法“主要”中,TV和DVDPlayer的对象是已知的,实际上是创建的。我们可以简单地执行tvObject.switchOn()和dvdPlayer.switchOn()。命令模式有何帮助

客户不必担心Receiver班级变化。Invoker直接在ConcreteCommand具有Receiver对象的上工作。Receiver对象将来可能会从siwtchOn()更改为switchOnDevice()。但是客户端交互不会改变。

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



 类似资料:
  • 7 宏命令        宏命令(Macro Command)又称为组合命令,它是组合模式和命令模式联用的产物。宏命令是一个具体命令类,它拥有一个集合属性,在该集合中包含了对其他命令对象的引用。通常宏命令不直接与请求接收者交互,而是通过它的成员来调用接收者的方法。当调用宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法,一个宏命令的成员可以是简单命令,还可以

  • 6 请求日志        请求日志就是将请求的历史记录保存下来,通常以日志文件(Log File)的形式永久存储在计算机中。很多系统都提供了日志文件,例如Windows日志文件、Oracle日志文件等,日志文件可以记录用户对系统的一些操作(例如对数据的更改)。请求日志文件可以实现很多功能,常用功能如下:        (1) “天有不测风云”,一旦系统发生故障,日志文件可以为系统提供一种恢复机制

  • 5 撤销操作的实现        在命令模式中,我们可以通过调用一个命令对象的execute()方法来实现对请求的处理,如果需要撤销(Undo)请求,可通过在命令类中增加一个逆向操作来实现。 扩展 除了通过一个逆向操作来实现撤销(Undo)外,还可以通过保存对象的历史状态来实现撤销,后者可使用备忘录模式(Memento Pattern)来实现。        下面通过一个简单的实例来学习如何使用命

  • 4 命令队列的实现        有时候我们需要将多个请求排队,当一个请求发送者发送一个请求时,将不止一个请求接收者产生响应,这些请求接收者将逐个执行业务方法,完成对请求的处理。此时,我们可以通过命令队列来实现。        命令队列的实现方法有多种形式,其中最常用、灵活性最好的一种方式是增加一个CommandQueue类,由该类来负责存储多个命令对象,而不同的命令对象可以对应不同的请求接收者,

  • 3 完整解决方案        为了降低功能键与功能处理类之间的耦合度,让用户可以自定义每一个功能键的功能,Sunny软件公司开发人员使用命令模式来设计“自定义功能键”模块,其核心结构如图4所示:   图4 自定义功能键核心结构图        在图4中,FBSettingWindow是“功能键设置”界面类,FunctionButton充当请求调用者,Command充当抽象命令类,Minimize

  •        装修新房的最后几道工序之一是安装插座和开关,通过开关可以控制一些电器的打开和关闭,例如电灯或者排气扇。在购买开关时,我们并不知道它将来到底用于控制什么电器,也就是说,开关与电灯、排气扇并无直接关系,一个开关在安装之后可能用来控制电灯,也可能用来控制排气扇或者其他电器设备。开关与电器之间通过电线建立连接,如果开关打开,则电线通电,电器工作;反之,开关关闭,电线断电,电器停止工作。相同的