《Head First 设计模式》学习笔记——命令模式

来源:互联网 发布:win10在端口23连接失败 编辑:程序博客网 时间:2024/05/17 15:41
在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象实现二者之间的松耦合。这就是命令模式(Command Pattern)————题记

设计模式
命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

模式分析
1. 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开
2. 每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作
3. 命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
4. 命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
5. 命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联

// Invoker:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。public class RemoteControl {//这时候,遥控器要处理7个开与关的命令,使用相应数组记录这些命令Command[] onCommands;Command[] offCommands; public RemoteControl() {//在构造器中,只需要实例化并初始化两个开与关的数组onCommands = new Command[7];offCommands = new Command[7];//NoCommand对象是一个空对象(null obeject)的例子。当你不想返回一个有意义的对象时,空对象就很有用,客户也可以将处理null的责任转义给空对象。//举例来说,遥控器不可能一出厂就设置了有意义的命令对象,所以提供了NoCommand对象作为替代品,当调用它的execute()//方法时,这种对象什么也不做。Command noCommand = new NoCommand();for (int i = 0; i < 7; i++) {onCommands[i] = noCommand;offCommands[i] = noCommand;}}  //setCommand()方法须有三个参数,分别是插槽的位置、开的命令、关的命令。public void setCommand(int slot, Command onCommand, Command offCommand) {onCommands[slot] = onCommand;offCommands[slot] = offCommand;} //当按下开或关的按钮,硬件就会负责调用对应的方法public void onButtonWasPushed(int slot) {onCommands[slot].execute();} public void offButtonWasPushed(int slot) {offCommands[slot].execute();}  //覆盖toString(),打印出每个插槽和它对应的命令。public String toString() {StringBuffer stringBuff = new StringBuffer();stringBuff.append("\n------ Remote Control -------\n");for (int i = 0; i < onCommands.length; i++) {stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName()+ "    " + offCommands[i].getClass().getName() + "\n");}return stringBuff.toString();}}//定义命令的接口,声明执行的方法。public interface Command {public void execute();}//命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。public class StereoOnWithCDCommand implements Command {Stereo stereo; public StereoOnWithCDCommand(Stereo stereo) {this.stereo = stereo;} public void execute() {stereo.on();stereo.setCD();stereo.setVolume(11);}}//接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。public class Stereo {String location;public Stereo(String location) {this.location = location;}public void on() {System.out.println(location + " stereo is on");}public void off() {System.out.println(location + " stereo is off");}public void setCD() {System.out.println(location + " stereo is set for CD input");}public void setDVD() {System.out.println(location + " stereo is set for DVD input");}public void setRadio() {System.out.println(location + " stereo is set for Radio");}public void setVolume(int volume) {// code to set the volume// valid range: 1-11 (after all 11 is better than 10, right?)System.out.println(location + " Stereo volume set to " + volume);}}//测试public class RemoteLoader { public static void main(String[] args) {RemoteControl remoteControl = new RemoteControl(); //将所有的装置创建在合适的位置Light livingRoomLight = new Light("Living Room");Light kitchenLight = new Light("Kitchen");CeilingFan ceilingFan= new CeilingFan("Living Room");GarageDoor garageDoor = new GarageDoor("");Stereo stereo = new Stereo("Living Room");  LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight);LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight);  CeilingFanOnCommand ceilingFanOn = new CeilingFanOnCommand(ceilingFan);CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan); GarageDoorUpCommand garageDoorUp =new GarageDoorUpCommand(garageDoor);GarageDoorDownCommand garageDoorDown =new GarageDoorDownCommand(garageDoor); StereoOnWithCDCommand stereoOnWithCD =new StereoOnWithCDCommand(stereo);StereoOffCommand  stereoOff =new StereoOffCommand(stereo); //现在已经有了全部的命令,可以将他们加载到遥控器插槽中。remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);remoteControl.setCommand(2, ceilingFanOn, ceilingFanOff);remoteControl.setCommand(3, stereoOnWithCD, stereoOff);  //在这里,使用toString()方法打印出每个遥控器的插槽和它被指定的命令System.out.println(remoteControl); //一切就绪,逐步按下每个插槽的开与关按钮。remoteControl.onButtonWasPushed(0);remoteControl.offButtonWasPushed(0);remoteControl.onButtonWasPushed(1);remoteControl.offButtonWasPushed(1);remoteControl.onButtonWasPushed(2);remoteControl.offButtonWasPushed(2);remoteControl.onButtonWasPushed(3);remoteControl.offButtonWasPushed(3);}}



0 0
原创粉丝点击