Java中的模式 --- 命令模式

xiaoxiao2021-03-01  13

一,命令模式的实现: 命令模式里边一般都有以下几个角色:客户端,请求者,命令接口,命令实现,接受者, 下边是简单命令模式的实现代码实现:  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和命令接受者的耦合,是命令请求和命令执行的对象分割 便于修改和扩张 便于聚合多个命令 缺点: 造成出现过多的具体命令类,太多文件。

五,一个比较有意思的例子,来说明命令模式 Client        :看电视的人 Invoker     :遥控器 Command :电信号 具体命令 :遥控器上的按键对应的不同的电信号 Receiver    :电视机 最后说一句,并不是全部按照模式写一定就好,应该根据你的需求来应用,或者全部应用,或者部分应用,或者根本不用。

转载请注明原文地址: https://www.6miu.com/read-3350146.html

最新回复(0)