java设计模式之Command(命令)

来源:互联网 发布:暴走大事件 恶劣 知乎 编辑:程序博客网 时间:2024/05/17 02:22

,命令模式的实现:
命令模式里边一般都有以下几个角色:客户端,请求者,命令接口,命令实现,接受者。
下边是简单命令模式的实现代码实现

1   public class Client {
2     public static void main(String[] args) {
3         Receiver receiver = new Receiver();
4         Command commandOne = new ConcreteCommandOne(receiver);
5         Command commandTwo = new ConcreteCommandTwo(receiver);
6         Invoker invoker = new Invoker(commandOne,commandTwo);
7         invoker.actionOne();
8         invoker.actionTwo();
9     }
10  }
11  public class Invoker {
12     private Command commandOne;
13     private Command commandTwo;
14     public Invoker(Command commandOne,Command commandTwo) {
15         this.commandOne = commandOne;
16         this.commandTwo = commandTwo;
17     }
18     public void actionOne() {
19         commandOne.execute();
20     }
21     public void actionTwo(){
22         commandTwo.execute();
23     }
24  }
25  public interface Command {
26     void execute();
27  }
28  public class ConcreteCommandOne implements Command{
29     private Receiver receiver
30     public ConcreteCommandOne(Receiver receiver) {
31         this.receiver = receiver;
32     }
33     public void execute() {
34         receiver.actionOne();
35     }
36  }
37  public class ConcreteCommandTwo implements Command {
38     private Receiver receiver
39     public ConcreteCommandTwo(Receiver receiver) {
40         this.receiver = receiver;
41     }
42     public void execute() {
43         receiver.actionTwo();
44     }
45  }
46  public class Receiver {
47     public Receiver() {
48         //
49     }
50     public void actionOne() {
51         System.out.println("ActionOne has been taken.");
52     }
53     public void actionTwo() {
54         System.out.println("ActionTwo has been taken.");
55     }
56  }
二,命令模式的功能,好处,或者说为什么使用命令模式?
上边的代码是否看起来很傻呢,本来可以这样简单实现的:
1  public class Client {
2     public static void main(String[] args) {
3         Receiver receiver = new Receiver();
4         receiver.actionOne();
5         receiver.actionTwo();
6     }
7  }
8  public class Receiver {
9     public Receiver() {
10         //
11     }
12     public void actionOne() {
13         System.out.println("ActionOne has been taken.");
14     }
15     public void actionTwo() {
16         System.out.println("ActionTwo has been taken.");
17     }
18  }

看多简洁,如果是像上边如此简单的需求,这个才应该是我们的选择,但是有些情况下这样的写法不能解决的,
或者说解决起来不好,所以引入命令模式.
(1)我们须要Client和Receiver同时开发,而且在开发过程中分别须要不停重购,改名
(2)如果我们要求Redo ,Undo等功能
(3)我们须要命令不按照调用执行,而是按照执行时的情况排序,执行
(4)开发后期,我们发现必须要log哪些方法执行了,如何在尽量少更改代码的情况下实现.并且渐少重复代码
(5)在上边的情况下,我们的接受者有很多,不止一个
解决办法:
情况一,我们可以定义一个接口,让Receiver实现这个接口,Client按照接口调用。
情况二,我们可以让Receiver记住一些状态,例如执行前的自己的状态,用来undo,但自己记录自己的状态
实现起来比较混乱,一般都是一个累记录另一个类的状态.
情况三,很难实现
情况四,,我们须要在每个Action,前后加上log
情况五,相对好实现,但是再加上这个,是否感觉最终的实现很混乱呢
好,我们再来看看命令模式,在命令模式中,我们增加一些过渡的类,这些类就是上边的命名接口和命令实现,
这样就很好的解决了情况一,情况二。我们再加入一个Invoker,这样情况三和情况四就比较好解决了。

如下加入Log和排序后的Invoker

1  public class Invoker {
2     private List cmdList = new ArrayList();
3     public Invoker() {
4     }
5     public add(Command command) {
6         cmdList.add(command);
7     }
8     public remove(Command command) {
9         cmdList.remove(command);
10     }
11     public void action() {
12         Command cmd;
13         while((cmd =getCmd()) != null) {
14             log("begin"+cmd.getName());
15             cmd.execute();
16             log("end"+cmd.getName());        
17         }
18     }
19     public Command getCmd() {
20         //按照自定义优先级,排序取出cmd
21     }
22  }
23  public class Client {
24     public static void main(String[] args) {
25         Receiver receiver = new Receiver();
26         Command commandOne = new ConcreteCommandOne(receiver);
27         Command commandTwo = new ConcreteCommandTwo(receiver);
28         Invoker invoker = new Invoker();
29         invoker.add(commandOne);
30         invoker.add(commandTwo);
31         iinvoker.action();
32     }
33  }

三,命令模式与其它模式的配合使用:
1,看上边的Invoker的实现是否很像代理模式呢,Invoker的这种实现其实就是一种代理模式。

2,需求:有个固定命令组合会多次被执行
    解决:加入合成模式,实现方法如下,定义一个宏命令类:

1  public class MacroCommand implements Command {
2     private List cmdList = new ArrayList();
3     public add(Command command) {
4         cmdList.add(command);
5     }
6     public remove(Command command) {
7         cmdList.remove(command);
8     }
9     public void execute() {
10         Command cmd;
11         for(int i=0;i<cmdList.size();i++) {
12             cmd = (Command)cmdList.get(i);
13             cmd.execute();
14         }
15     }    
16  }
3,需求:须要redo undo
   解决:加入备忘录模式,一个简单的实现如下
1  public class ConcreteCommandOne implements Command {
2     private Receiver receiver
3     private Receiver lastReceiver;
4     public ConcreteCommandOne(Receiver receiver) {
5         this.receiver = receiver;
6     }
7     public void execute() {
8         record();
9         receiver.actionOne();
10     }
11     public void undo() {
12         //恢复状态
13     }
14     public void redo() {
15         lastReceiver.actionOne();
16         //
17     }
18     public record() {
19         //记录状态
20     }
21  }
4,需求:命令很多类似的地方
    解决:使用原型模式,利用clone
    这个就不写例子了。
四,命令模式的使用场合
1,须要callback的时候,例如java awt/swing/swt中的Listening的消息方式
2,须要对请求排队执行,命令的发送者和接受者有不同对的生命周期,就是命令执行的时候,可能发出命令的
Client已经不存在了
3,须要Redo Undo等函数
4,须要log每条命令
5,须要支持transaction,封装一组数据命令的时候.
五,最后再次总结一下命令模式的优点和缺点:
优点:
降低Client和命令接受者的耦合,是命令请求和命令执行的对象分割
便于修改和扩张
便于聚合多个命令
缺点:
造成出现过多的具体命令类,太多文件。