命令(command)模式

来源:互联网 发布:ktv 知乎 编辑:程序博客网 时间:2024/06/03 02:48
材料内容均取自head first dp

一、简介

命令模式是将请求(命令)封装为对象。以便于使用不同的请求(队列或者日志)来参数化其他对象。

命令模式把发出命令的责任(invoker)和执行命令的责任(receiver)分割开。

关于命令模式

1.命令模式将发出请求的对象和执行请求的对象解耦

2.在被解耦的两者之间间是通过命令对象进行沟通的,命令对象封装了一个或一组动作

3.调用者通过调用命令对象的execute方法发出请求,这使得接收者对象的劢作被调用

4.宏命令是命令的一种简单延伸,允许调用多个命令

 

二、遥控器控制家电的例子

       有一个综合遥控器(remoteController),可以控制点灯(light)的开关,电视(TV)的开关等等。然后电灯的开关和电视的开关方式不同,如何可扩展的集中到一个遥控器上,例如当增加新的电器空调时,可以遵循开闭原则,不更改现有代码。

       在这个例子中,主人作为client来操作所有电器。remoteController作为一个invoker,因为主人直接操作的是遥控器来控制各个电器,而电灯、电视等当然是以receiver的身份出现。我们这里需要抽象出command,以及实现控制具体家电的command。


Command(命令)接口

 

Java代码  收藏代码
  1.  
  2. public interface Command {  
  3.     //命令对象方法  
  4.     public void execute();  
  5. }  

 

遥控器(发出命令对象)类:RemoteControl.java 

 

Java代码  收藏代码
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. public class RemoteControl {  
  5.       
  6.     //用于存放命令  
  7.     private List<Command> commandList = new ArrayList<Command>();  
  8.       
  9.     /** 
  10.      * 向遥控器中添加命令 
  11.      * @param command 
  12.      */  
  13.     public void setCommand(Command command){  
  14.         commandList.add(command);  
  15.     }  
  16.       
  17.     /** 
  18.      * 按下按键执行第几个命令 
  19.      * @param index 
  20.      */  
  21.     public void buttonWasPressed(int index){  
  22.         commandList.get(index - 1).execute();  
  23.     }  
  24. }  

 

两个电器(执行命令对象):电灯类、电视类

 

Java代码  收藏代码
  1. //1.电灯类  
  2. public class Light {  
  3.     public void on(){  
  4.         System.out.println("灯亮了!");  
  5.     }  
  6. }  

 

 

 

Java代码  收藏代码
  1. //2.电视类  
  2. public class Tv {  
  3.     public void on(){  
  4.         System.out.println("打开电视!");  
  5.     }  
  6. }  
 两个命令对象类(实现Command接口):控制电灯、控制电视

 Java代码  收藏代码

  1. //1.控制电灯  
  2. public class LightOnCommand implements Command{  
  3.   
  4.     private Light light;  
  5.       
  6.     /** 
  7.      * 传入控制的对象:电灯 
  8.      * @param light 
  9.      */  
  10.     public LightOnCommand(Light light){  
  11.         this.light = light;  
  12.     }  
  13.       
  14.     /** 
  15.      * 执行命令:打开灯 
  16.      */  
  17.     @Override  
  18.     public void execute() {  
  19.         light.on();  
  20.     }  
  21.       
  22. }  

  Java代码  收藏代码

  1. //2.控制电视  
  2. public class TurnTvCommand implements Command{  
  3.   
  4.     private Tv tv;  
  5.       
  6.     public TurnTvCommand (Tv tv){  
  7.         this.tv = tv;  
  8.     }  
  9.     @Override  
  10.     public void execute() {  
  11.         tv.on();  
  12.     }  
  13.   
  14. }  
测试类Client 
Java代码  收藏代码
  1. package com.kaishengit.command;  
  2.   
  3. public class Test {  
  4.     public static void main(String[] args) {  
  5.         //创建遥控器  
  6.         RemoteControl remoteControl = new RemoteControl();  
  7.         //开灯命令  
  8.         LightOnCommand lightOnCommand  = new LightOnCommand(new Light());  
  9.         //打开电视命令  
  10.         TurnTvCommand turnTvCommand = new TurnTvCommand(new Tv());  
  11.           
  12.         //将命令捆绑到遥控器上  
  13.         remoteControl.setCommand(turnTvCommand);  
  14.         remoteControl.setCommand(lightOnCommand);  
  15.           
  16.         //按下按钮  
  17.         remoteControl.buttonWasPressed(1);//执行第一个命令  
  18.         //remoteControl.buttonWasPressed(2);//执行第二个命令  
  19.     }  
  20. }  


宏命令:是对子命令的结合体,一连串命令。

比如这里,我们创建一个宏命令:先开灯,再开电视


宏命令对象(实现Command接口):MacroCommand.java 

 Java代码  收藏代码

  1. //宏命令  
  2. public class MacroCommand implements Command{  
  3.   
  4.     private Command[] commands;  
  5.       
  6.     /** 
  7.      * 传入命令列表 
  8.      * @param commands 
  9.      */  
  10.     public MacroCommand(Command...commands){  
  11.         this.commands = commands;  
  12.     }  
  13.       
  14.     /** 
  15.      * 依次执行命令列表中的命令 
  16.      */  
  17.     @Override  
  18.     public void execute() {  
  19.         for(Command command : commands){  
  20.             command.execute();  
  21.         }  
  22.     }  
  23.       
  24. }  

试一下我们新建的宏命令对象

 Java代码  收藏代码

  1. package com.kaishengit.command;  
  2.   
  3. public class Test {  
  4.     public static void main(String[] args) {  
  5.         //创建遥控器  
  6.         RemoteControl remoteControl = new RemoteControl();  
  7.           
  8.         //开灯命令  
  9.         LightOnCommand lightOnCommand  = new LightOnCommand(new Light());  
  10.         //开电视命令  
  11.         TurnTvCommand turnTvCommand = new TurnTvCommand(new Tv());  
  12.           
  13.         //我们创建的宏命令,传入命令列表:1.开灯命令、2.开电视命令  
  14.         MacroCommand mc = new MacroCommand(lightOnCommand,turnTvCommand);  
  15.           
  16.         //将宏命令捆绑到遥控器上  
  17.         remoteControl.setCommand(mc);  
  18.       
  19.         //按下按钮,执行宏命令  
  20.         remoteControl.buttonWasPressed(1);  
  21.     }  
  22. }  

三、命令模式的拓展

命令模式支持undo操作,日志操作和事物操作等,如果做到呢?

我们可以在remoteController中增加一个栈域,每undo一次,从栈中弹出上一次的操作。日志也是在invoker中记录所有的操作。事物其实就undo操作的完整版了,当遇到异常时rollback,rollback的依据,也就是invoker中记录的操作。

原创粉丝点击