命令模式 将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
说明: 1、命令模式将发出请求的对象和执行请求的对象解耦;
2、在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接受者和一个或一组动作;
3、调用者通过调用命令对象的execute()发出请求,这会使得接受者的动作被调用;
4、调用者可以接受命令当做参数,甚至在运行时动态地进行;
5、命令可以支持撤销,做法事实现一个undo()方法来回到exexcute()被执行前的状态;
6、命令模式也可以用来实现日志和事物系统;
优点: 1、降低对象之间的耦合度;
2、新的命令可以很容易地加入到系统中;
3、可以比较容易地设计一个组合命令;
4、调用同一方法实现不同的功能。
缺点: 使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
场景: 1、系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互;
2、系统需要在不同的时间指定请求、将请求排队和执行请求;
3、系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作;
4、系统需要将一组操作组合在一起,即支持宏命令;
例子: 录音机有播音(Play)、倒带(Re
wind)和停止(Stop)功能,录音机的键盘便是请求者(Invoker)角色;Leslie是客户端角色,而录音机便是接收者角色。Command类扮演抽象命令角色,而PlayCommand、StopCommand和RewindCommand便是具体命令类。Leslie不需要知道播音(play)、倒带(rewind)和停止(stop)功能是怎么具体执行的,这些命令执行的细节全都由键盘(Keypad)具体实施。Leslie只需要在键盘上按下相应的键便可以了。
/** * 命令接口。 * 所有的命令对象需要实现该接口。 * */ public interface Commond { public void execute(); }
|
/** * 录音机--命令接受者 * */ public class AudioPlayer { public void play() { System.out.println("播放......"); } public void stop() { System.out.println("暂停......"); } public void rewind() { System.out.println("倒带......"); } }
|
/** * 录音机播放命令 * 具体命令角色类 * */ public class PlayCommond implements Commond{ AudioPlayer player; public PlayCommond(AudioPlayer player) { this.player = player; } // 调用接收对象(录音机)的 play() 方法 public void execute() { player.play(); } }
|
/** * 录音机倒带命令 * 具体命令角色类 * */ public class RewindCommond implements Commond{ AudioPlayer player; public RewindCommond(AudioPlayer player) { this.player = player; } // 调用接收对象(录音机)的 rewind() 方法 public void execute() { player.rewind(); } }
|
/** * 录音机暂停命令 * 具体命令角色类 * */ public class StopCommond implements Commond{ AudioPlayer player; public StopCommond(AudioPlayer player) { this.player = player; } // 调用接收对象(录音机)的 stop() 方法 public void execute() { player.stop(); } }
|
/** * 键盘类 * 请求者角色 * */ public class Keypad { private Commond play; private Commond stop; private Commond rewind; public void setPlayCommond(Commond play) { this.play = play; } public void setStopCommond(Commond stop) { this.stop = stop; } public void setRewindCommond(Commond rewind) { this.rewind = rewind; } // 执行播放方法 public void play() { play.execute(); } // 执行暂停方法 public void stop() { stop.execute(); } // 执行倒带方法 public void rewind() { rewind.execute(); } }
|
/** * 具体人--莱斯利 * 客户端角色 * */ public class Leslie { public static void main(String[] args) { // 创建接受者对象,即收音机对象 AudioPlayer player = new AudioPlayer(); // 创建命令者对象 Commond play = new PlayCommond(player); Commond stop = new StopCommond(player); Commond rewind = new RewindCommond(player); // 创建请求者对象,即键盘对象 Keypad keypad = new Keypad(); keypad.setPlayCommond(play); keypad.setStopCommond(stop); keypad.setRewindCommond(rewind); // 播放 keypad.play(); // 暂停 keypad.stop(); // 倒带 keypad.rewind(); } }
|
宏命令 所谓宏命令简单点说就是包含多个命令的命令,是一个命令的组合。
设想Leslie 的录音机有一个记录功能,可以把一个一个的命令记录下来,再在任何需要的时候重新把这些记录下来的命令一次性执行,这就是所谓的宏命令集功能。因此,Leslie 的录音机系统现在有四个键,分别为播音、倒带、停止和宏命令功能。此时系统的设计与前面的设计相比有所增强,主要体现在Julia类现在有了一个新方法,用以操作宏命令键。
/** * 定义宏命令接口 * */ public interface MacroCommand extends Command{ /** * 宏命令存储的管理方法 * 可以添加一个成员命令 */ public void add(Command cmd); /** * 宏命令存储的管理方法 * 可以删除一个成员命令 */ public void remove(Command cmd); }
|
/** * 具体的宏命令,对存储的若干命令进行操作 * */ public class MacroAudioCommand implements MacroCommand{ // 宏命令集合 private List<Command> cmdList = new ArrayList<Command>(); // 一次性执行宏命令集合中的各命令 public void execute() { System.out.println("-------自动回放保存的命令-------"); for(Command cmd : cmdList) { cmd.execute(); } System.out.println("------------回放完毕------------"); } public void add(Command cmd) { cmdList.add(cmd); } public void remove(Command cmd) { cmdList.remove(cmd); } }
|
/** * 具体人--莱斯利 * 客户端角色 * */ public class Leslie { public static void main(String[] args) { // 创建接受者对象,即收音机对象 AudioPlayer player = new AudioPlayer(); // 创建命令者对象 Command play = new PlayCommond(player); Command stop = new StopCommond(player); Command rewind = new RewindCommond(player); MacroCommand macro = new MacroAudioCommand(); macro.add(play); macro.add(rewind); macro.add(stop); macro.execute(); } }
|
参考资料:《Head First
设计模式》
http://blog.csdn.net/jason0539/article/details/45110355
http://www.cnblogs.com/java-my-life/archive/2012/06/01/2526972.html
原标题:设计模式学习笔记之命令模式
关键词:设计模式