nit*_*.kk 6 java design-patterns command-pattern
Command 模式有一个 IReceiver 接口,其中有几个方法,并且与每个方法相对应,有具体的 Command 对象(实现一个接口ICommand)。
我读到客户端知道具体接收器和具体命令,并且通常是客户端在具体命令对象中设置接收器对象。那为什么说它解耦了发送者和接收者呢?
当客户端已经知道具体的接收者时,我觉得这不是松耦合,而且在这种情况下客户端可以直接调用接收者对象上的 API(方法)。
您可以将命令模式工作流程视为如下。
Command为所有命令声明一个接口,提供一个简单的execute()方法,要求命令的接收者执行操作。
他们Receiver知道如何执行请求。
持有Invoker一个命令,可以Command通过调用execute方法来执行请求。
创建并设置命令的a Client。ConcreteCommandsReceiver
定义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();
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
java CommandDemoEx
Switch on from:TV
Switch on from:DVDPlayer
Run Code Online (Sandbox Code Playgroud)
回答你的问题:
我读过客户端了解具体接收器和具体命令,通常是客户端在具体命令对象中设置接收器对象。那为什么说它解耦了发送者和接收者
为了标准化词语,请将“发送者”替换为“调用者”。现在看一下代码。
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();
Run Code Online (Sandbox Code Playgroud)
=>
Invoker invoker = new Invoker(new ConcreteCommand());
invoker.start()
Run Code Online (Sandbox Code Playgroud)
并且您在 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();
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
在您的最后一个查询中
这里我们创建了命令对象、接收者对象和调用者对象。然后将接收者对象传递给命令对象,然后将命令对象传递给调用者对象。我们为每个接收器执行此操作,就像我们在此处为电视和 DVD 播放器执行的操作一样。此外,在方法中,TV 和 DVDPlayer 的“主”对象是已知的并且实际上是被创建的。我们可以简单地执行 tvObject.switchOn() 和 dvdPlayer.switchOn()。命令模式有何帮助
客户无需担心Receiver班级的变化。Invoker直接作用于ConcreteCommand,它有Receiver对象。Receiver对象将来可能会siwtchOn从 ()变为 ()。switchOnDevice但客户端交互并没有改变。
如果您有两个不同的命令,例如switchOn() 和switchOff(),您仍然可以使用相同的Invoker.