《《命令模式》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《命令模式》PPT课件.ppt(43页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第十一章第十一章 命令模式命令模式家电自动化遥控器的家电自动化遥控器的API遥控器有七个可编程的插槽(每个控制一个不同的家电自动化装置),每个插槽有对应的开开(on)/关关(off)按钮;有一个撤消撤消(undo)按钮。有一组Java类,这些类是由多家厂商开发出来的,用来控制家电装置,例如电灯、风扇、热水器、音响设备等。1遥控遥控器器2厂商厂商类类喷头立体声音响水龙头热水器恒温器厨具控制3家电自动化遥控器的家电自动化遥控器的API(续续)目标目标:创建一组控制遥控器的API,每个插槽能控制一个或一组装置(包括目前的装置和未来可能的装置)。问题问题:有许多厂商类,每个类有各自的操作。遥控器应该怎
2、样解读按钮被按下的动作?解决方法解决方法:采用“命令对象”封装动作请求。当按钮按下时,请命令对象做相关的工作。让“动作的请求者(遥控器)”从“动作的执行者(厂商类之一的实例)”对象中解耦。4餐厅订餐餐厅订餐5更详细地研究刚才的交互过程。6从餐厅到命令模式从餐厅到命令模式与订餐过程的略微不同之处:客户一般不会直接指定厨师。7实现命令接口实现命令接口 所有的命令对象命令对象实现相同的包含一个方法的接口。在餐厅中,此方法为orderUp(),命令对象中惯用名称execute()。public interface Command public void execute();只有这一个方法。8实现一个打
3、开电灯的命令实现一个打开电灯的命令 根据厂商提供的类,light有两个方法:on()和off()。public class LightOnCommand implements Command Light light;public LightOnCommand(Light light)=light;public void execute()();9使用命令对象使用命令对象 假定遥控器只有一个按钮和对应的插槽:public class SimpleRemoteControl()Command slot;public SimpleRemoteControl()public void setComma
4、nd(Command command)slot=command;public void buttonWasPressed()();设置插槽控制的命令。如果要改变遥控器的行为,可以重复调用这个方法。遥控器的角色是“调调用者用者”。10遥控器使用的简单测试遥控器使用的简单测试public class RemoteControlTest public class static void main(String args)SimpleRemoteControl remote=new SimpleRemoteControl();Light light=new Light();LightOnCommand
5、 lightOn=new LightOnCommand(light);remote.setCommand(lightOn);();客户调用者创建一个命令对象接收者命令传给调用者调用者执行命令11命令模式定义命令模式定义 利用命令来参数化对象。遥控器对象并不关心是什么命令对象,只要该命令对象实现了Command接口即可。命令模式也可以实现队列、日志和撤消操作。12命令模式类图命令模式类图13将命令指定到插槽将命令指定到插槽 将遥控器的每个插槽,对应到一个命令,把遥控器变成“调用者调用者”。当按下按钮,相应命令对象的execute()方法就会被调用,使得接收者的动作被调用。1415实现遥控器实现遥
6、控器public class RemoteControl Command onCommands;Command offCommands;public RemoteControl()onCommands=new Command7;offCommands=new Command7;Command noCommand=new NoCommand();for(int i=0;i 7;i+)onCommandsi=noCommand;offCommandsi=noCommand;public void setCommand(int slot,Command onCommand,Command offCo
7、mmand)onCommandsslot=onCommand;offCommandsslot=offCommand;16实现遥控器实现遥控器(续续)public void onButtonWasPushed(int slot)onCommandsslot.execute();public void offButtonWasPushed(int slot)offCommandsslot.execute();public String toString()/覆盖toString(),打印出每个插槽和它对应的命令。StringBuffer stringBuff=new StringBuffer();
8、stringBuff.append(n-Remote Control-n);for(int i=0;i ;i+)stringBuff.append(slot +i+onCommandsi.getClass().getName()+offCommandsi.getClass().getName()+n);return();17实现命令实现命令 LightOnCommand与前面的一样,LightOffCommand也是类似的。public class LightOffCommand implements Command Light light;public LightOffCommand(Lig
9、ht light)=light;public void execute()();18实现命令实现命令(续续)StereoOffCommand很简单,下面给出StereoOnWithCDCommand:public class StereoOnWithCDCommand implements Command Stereo stereo;public StereoOnWithCDCommand(Stereo stereo)=stereo;public void execute()();();stereo.setVolume(11);实现这个请求需要调用音响的三个方法:首先打开它,然后设置成播放CD
10、,最后把音量设置成11。19测试遥控器测试遥控器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 GarageD
11、oor();Stereo stereo=new Stereo(Living Room);所有装置创建在合适的位置。客户调用者20测试遥控器测试遥控器(续续)LightOnCommand livingRoomLightOn=new LightOnCommand(livingRoomLight);LightOffCommand livingRoomLightOff=new LightOffCommand(livingRoomLight);LightOnCommand kitchenLightOn=new LightOnCommand(kitchenLight);LightOffCommand ki
12、tchenLightOff=new LightOffCommand(kitchenLight);创建所有电灯命令对象。21测试遥控器测试遥控器(续续)CeilingFanOnCommand ceilingFanOn=new CeilingFanOnCommand(ceilingFan);CeilingFanOffCommand ceilingFanOff=new CeilingFanOffCommand(ceilingFan);GarageDoorUpCommand garageDoorUp=new GarageDoorUpCommand(garageDoor);GarageDoorDownC
13、ommand garageDoorDown=new GarageDoorDownCommand(garageDoor);创建掉扇开与关命令。创建车库门上与下的命令。22测试遥控器测试遥控器(续续)StereoOnWithCDCommand stereoOnWithCD=new StereoOnWithCDCommand(stereo);StereoOffCommand stereoOff=new StereoOffCommand(stereo);remoteControl.setCommand(0,livingRoomLightOn,livingRoomLightOff);remoteCont
14、rol.setCommand(1,kitchenLightOn,kitchenLightOff);remoteControl.setCommand(2,ceilingFanOn,ceilingFanOff);remoteControl.setCommand(3,stereoOnWithCD,stereoOff);创建音响开与关命令。所有命令加载到遥控器插槽中。23测试遥控器测试遥控器(续续)System.out.println(remoteControl);remoteControl.onButtonWasPushed(0);remoteControl.offButtonWasPushed(0
15、);remoteControl.onButtonWasPushed(1);remoteControl.offButtonWasPushed(1);remoteControl.onButtonWasPushed(2);remoteControl.offButtonWasPushed(2);remoteControl.onButtonWasPushed(3);remoteControl.offButtonWasPushed(3);用toString()方法打印遥控器每个插槽指定的命令。按下每个插槽开与关命令。24测试结果测试结果开启开启插槽插槽关闭关闭插槽插槽命令执命令执行结果行结果25NoCom
16、mand对象对象 NoCommand对象是一个空对象(null object)。在遥控器中,我们不想每次都检查某个插槽是否加载了命令。我们将每个插糟都预先指定NoCommand对象,以便确定每个插槽永远都有命令对象。否则,需要类似下面的代码:public void onButtonWasPushed(int slot)if(onCommandsslot!=null)onCommandsslot.execute();26遥控器遥控器API27支持支持undo功能功能(以电灯为例以电灯为例)在Command接口中加入undo()方法。public interface Command public
17、void execute();public void undo();从LightOnCommand开始下手。public class LightOnCommand implements CommandLight light;public LightOnCommand(Light light)this light=light;public void execute()();public void undo()();execute()打开电灯,undo()就是关闭电灯。28支持支持undo功能功能(以电灯为例以电灯为例)(续续)public class LightOffCommand implem
18、ents CommandLight light;public LightOffCommand(Light light)this light=light;public void execute()();public void undo()();undo()把电灯打开。29支持支持undo功能功能(续续)修改遥控器类。加入一个新的实例变量,追踪最后被调用的命令。public class RemoteControlWithUndo Command onCommands;Command offCommands;Command undoCommand;public RemoteControlWithUn
19、do()onCommands=new Command7;offCommands=new Command7;Command noCommand=new NoCommand();for(int i=0;i7;i+)onCommandsi=noCommand;offCommandsi=noCommand;undoCommand=noCommand;30public void setCommand(int slot,Command onCommand,Command offCommand)onCommandsslot=onCommand;offCommandsslot=offCommand;publi
20、c void onButtonWasPushed(int slot)onCommandsslot.execute();undoCommand=onCommandsslot;public void offButtonWasPushed(int slot)offCommandsslot.execute();undoCommand=offCommandsslot;public void undoButtonWasPushed()();public String toString()/toString代码 undoCommand变量记录按钮命令。调用undoCommand实例变量的undo()方法。3
21、1测试测试undo按钮按钮public class RemoteLoader public static void main(String args)RemoteControlWithUndo remoteControl=new RemoteControlWithUndo();Light livingRoomLight=new Light(Living Room);LightOnCommand livingRoomLightOn=new LightOnCommand(livingRoomLight);LightOffCommand livingRoomLightOff=new lightOff
22、Command(livingRoomLight);remoteControl.setCommand(0,livingRoomLightOn,livingRoomLightOff);remoteControl.onButtonWasPushed(0);remoteControl.offButtonWasPushed(0);System.out.println(remoteControl);();remoteControl.offButtonWasPushed(0);remoteControl.onButtonWasPushed(0);System.out.println(remoteContro
23、l);();打开、关闭电打开、关闭电灯灯,然后撤消。然后撤消。关闭、打开电关闭、打开电灯灯,然后撤消。然后撤消。32测试结果测试结果打开电灯,关闭电灯。电灯命令。按下撤消按钮。undo记录的命令。33使用状态实现使用状态实现undo要实现撤消的功能,通常需要记录一些状态。下面以天花板上的掉扇为例说明。public class CeilingFan public static final int HIGH=3;public static final int MEDIUM=2;public static final int LOW=1;public static final int OFF=0;S
24、tring location;/例如客厅int speed;public CeilingFan(String location)=location;speed=OFF;public void high()/设置高转速 public void medium()/设置中转速 public void low()/设置中转速 public void off()/关闭掉扇 public int getSpeed()return speed;34加入加入undo到掉扇命令类到掉扇命令类 public class CeilingFanHighCommand implements Command Ceilin
25、gFan ceilingFan;int prevSpeed;public CeilingFanHighCommand(CeilingFan ceilingFan)=ceilingFan;public void execute()prevSpeed=();();public void undo()if(prevSpeed=)();else if(prevSpeed=)();else if(prevSpeed=)();else if(prevSpeed=)();记录掉扇之前的速度变量。记录掉扇之前的速度。掉扇速度设置回之前的值。35测试天花板掉扇测试天花板掉扇public class Remote
26、Loader public static void main(String args)RemoteControlWithUndo remoteControl=new RemoteControlWithUndo();CeilingFan ceilingFan=new CeilingFan(Living Room);CeilingFanMediumCommand ceilingFanMedium=new CeilingFanMediumCommand(ceilingFan);CeilingFanHighCommand ceilingFanHigh=new CeilingFanHighCommand
27、(ceilingFan);CeilingFanOffCommand ceilingFanOff=new CeilingFanOffCommand(ceilingFan);remoteControl.setCommand(0,ceilingFanMedium,ceilingFanOff);remoteControl.setCommand(1,ceilingFanHigh,ceilingFanOff);remoteControl.onButtonWasPushed(0);remoteControl.offButtonWasPushed(0);System.out.println(remoteCon
28、trol);();remoteControl.onButtonWasPushed(1);System.out.println(remoteControl);();实例化高速、中速和关闭三个命令。中速设置到0号插槽,高速设置到1号插槽并加载两个插槽的关闭命令。中中速速高高速速36测试结果测试结果中速打开天花板掉扇,然后关闭。遥控器命令。撤消最后一个命令,回到中速。撤消最后一个命令,回到中速。打开高速。打开高速。再一次撤消,回到中速。37使用宏命令使用宏命令 首先创建宏命令集合。Light light=new Light(Living Room);TV tv=new TV(Living Room)
29、;Stereo stereo=new Stereo(Living Room);Hottub hottub=new Hottub();LightOnCommand lightOn=new LightOnCommand(light);StereoOnCommand stereoOn=new StereoOnCommand(stereo);TVOnCommand tvOn=new TVOnCommand(tv);HottubOnCommand hottubOn=new ottubOnCommand(hottub);创建所有的装置:电灯、电视、音响和热水器。38使用宏命令使用宏命令(续续)创建两个数组
30、,记录打开和关闭命令。Command partyOn=lightOn,stereoOn,tvOn,hottubOn;Command partyOff=lightOff,stereoOff,tvOff,hottubOff;MacroCommand partyOnMacro=new MacroCommand(partyOn);MacroCommand partyOffMacro=new MacroCommand(partyOff);public class MacroCommand implements Command Command commands;public MacroCommand(Co
31、mmand commands)=commands;public void execute()for(int i=0;i ;i+)commandsi.execute();数组存储一堆命令。一次性执行数组里的每一个命令。39使用宏命令使用宏命令(续续)宏命令指定到一个按钮。remoteControl.setCommand(0,partyOnMacro,partyOffMacro);测试是否正常工作。System.out.println(remoteControl);(-Pushing Macro On-);remoteControl.onButtonWasPushed(0);(-Pushing Macro Off-);remoteControl.offButtonWasPushed(0);40测试结果测试结果开启宏。关闭宏。41命令模式更多用途:队列请求命令模式更多用途:队列请求工作队列类和进行计算的对象之间是完全解耦的。工作队列不在乎命令做什么,只知道取出命令对象,调用其execute()方法。多线程处理。多线程处理。42命令模式更多用途:日志请求命令模式更多用途:日志请求某些应用需要将所有动作记录在日志中,并能在系统死机后重新调用这些动作恢复到之前的状态。命令接口中新增store()和load()两个方法。43
限制150内