您可以将命令模式的工作流程想象如下。
Command 为所有命令声明了一个接口,提供了一个简单的 execute() 方法,该方法要求命令的接收者执行操作。
Receiver 知道如何执行请求。
Invoker持有命令,可以通过调用execute方法获取Command执行请求。
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
回答你的问题:
我读过客户端知道具体的接收器和具体的命令,通常是客户端在具体的命令对象中设置接收器对象。那为什么说它使发送者和接收者解耦
为了标准化单词,将“sender”替换为“invoker”。现在通过代码。
-
Invoker simply executes the ConcreteCommand(在本例中为 OnCommand)通过传递 ConcreteReceiver。
-
ConcreteCommand executes Command 通过 ConcreteReceiver 即ConcreteCommand defines binding between Action and Receiver.
- 如果您看到工作流,Invoker 不会随着附加命令而改变,您可以在 Invoker 的
execute() 方法中添加业务逻辑,如 java.lang.Thread,解释如下。
- 这样
Client (sender) and Receiver are loosely couple through Invoker, which has knowledge of what command to be executed。
线程示例来自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();
}
}
编辑:
关于您的最后一个查询
这里我们创建命令对象、接收者对象和调用者对象。然后在命令对象中传递接收者对象,然后在调用者对象中传递命令对象。我们对每个接收器执行此操作,就像我们在此处对 TV 和 DVDPlayer 执行的操作一样。同样在方法中,TV 和 DVDPlayer 的“主要”对象是已知的并且实际上是创建的。我们可以简单地执行 tvObject.switchOn() 和 dvdPlayer.switchOn()。命令模式有什么帮助
客户不必担心Receiver 类的变化。 Invoker 直接作用于具有Receiver 对象的ConcreteCommand。 Receiver 对象将来可能会将 siwtchOn() 更改为 switchOnDevice()。但是客户端交互不会改变。
如果你有两个不同的命令,比如switchOn() 和switchOff(),你仍然可以使用相同的Invoker。