Command模式具有一个IReceiver接口,该接口带有很少的方法,并且与每个方法相对应的都是具体的Command对象(ICommand
使用execute()方法实现接口)。
我了解到,客户端了解具体的接收方和具体命令,通常是客户在具体的命令对象中设置接收方对象。那么为什么说它使发送者和接收者分离呢?
当客户端已经知道具体的接收方时,我认为这并不是松散的耦合,并且在这种情况下,客户端也可以直接在接收方对象上调用API(方法)。
您可以想到以下命令模式工作流程。
Command
声明所有命令的接口,并提供一个简单的execute()方法,该方法要求命令Receiver进行操作。
该Receiver
有怎样做才能执行请求的知识。
该Invoker
持有命令可以得到Command
通过调用execute方法来执行请求。
在Client
创建ConcreteCommands
并设置Receiver
该命令。
的ConcreteCommand
限定的动作和所述接收器之间的结合。
当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”。现在查看代码。
Invoker simply executes the ConcreteCommand
(在这种情况下为OnCommand)通过传递ConcreteReceiver。 ConcreteCommand executes Command
通过ConcreteReceiver即 ConcreteCommand defines binding between Action and Receiver.
execute()
Invoker方法中添加业务逻辑,例如java.lang.Thread,如下所述。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
装修新房的最后几道工序之一是安装插座和开关,通过开关可以控制一些电器的打开和关闭,例如电灯或者排气扇。在购买开关时,我们并不知道它将来到底用于控制什么电器,也就是说,开关与电灯、排气扇并无直接关系,一个开关在安装之后可能用来控制电灯,也可能用来控制排气扇或者其他电器设备。开关与电器之间通过电线建立连接,如果开关打开,则电线通电,电器工作;反之,开关关闭,电线断电,电器停止工作。相同的