命令模式:将请求封装成对象,使动作的请求者从动作的执行者对象中解耦,这可以让你使用不同的请求、队列,或者日志请求来参数化其他对象,。命令模式也可以支持撤销操作,是一种对象行为性模式。
话不多说:直接上实例:
下面我们来实现一个家电自动化遥控器的api,一个遥控器,双排按钮,控制一堆家电的开关的操作。就这么个事
差不多有这些厂家类:
1.先把它要的这些类写好
//灯
class Light2{
public String name ;
public void on(){}
public void off(){}
}
//天花板灯
class CeilingLight extends Light2{
public CeilingLight(String name){
this.name = name;
}
public void on(){
System.out.println("已经为您打开天花板的灯。。");
}
public void off(){
System.out.println("已经为您关上天花板的灯。。");
}
public void dim(){
System.out.println("已经为您调暗天花板的灯。。");
}
}
//室外灯
class OutDoorLight2 extends Light2{
public void on(){
System.out.println("正在为您打开室外灯。。");
}
public void off(){
System.out.println("正在为您关闭室外灯。。");
}
}
//花园灯
class GardenLight2 extends Light2{
public void setDuskTime(){
System.out.println("已经为您设置黄昏时间打开灯。。");
}
public void setDawnTime(){
System.out.println("已经为您设置黎明时间关闭灯。。");
}
}
//吊扇
class CeilingFan{
public void high(){
System.out.println("正在为您升高吊扇。。");
}
public void medium(){
System.out.println("吊扇已为您调到适中位置。。");
}
public void low(){
System.out.println("正在问您降低吊扇。。");
}
public void off(){
System.out.println("已经为您关闭吊扇。。");
}
public void getSpeed(){
System.out.println("正在为您将吊扇调到适宜位置。。");
}
}
//洒水器
class Sprinkler{
public void waterOn(){
System.out.println("已经为您打开洒水器。。");
}
public void waterOff(){
System.out.println("已经为您关闭洒水器。。");
}
}
//电视
class TV{
public void on(){
System.out.println("已经为您打开电视。。");
}
public void off(){
System.out.println("已经为您关闭电视。。");
}
public void setInputChannel(){
System.out.println("正在为您选择频道。。");
}
public void setVolumn(){
System.out.println("正在为您调节音量。。");
}
}
//车库门
class GarageDoor{
public void up(){
System.out.println("正在为你生起车库门。。");
}
public void down(){
System.out.println("正在为您关闭车库门。。");
}
public void stop(){
System.out.println("正在为您固定车库门。。");
}
public void lightOn(){
System.out.println("正在为您打开车库门的灯。。");
}
public void lightOff(){
System.out.println("正在为您关闭车库门的灯。。");
}
}
//应用控制
class ApplicationControl{
public void on(){
System.out.println("正在为您打开应用控制。。");
}
public void off(){
System.out.println("正在为您关闭应用控制。。");
}
}
//立体声
class Stereo2{
public void on(){
System.out.println("已经为您打开音响。。");
}
public void off(){
System.out.println("已经为您关闭音响。。");
}
public void setCD(){
System.out.println("已经为您放好CD光盘。。");
}
public void setDVD(){
System.out.println("已经为您放好dvd光盘。。");
}
public void setVolume(){
System.out.println("正在为您调节立体声音量。。");
}
}
//水龙头控制
class FaucetControl{
public void openValue(){
System.out.println("正在为您打开水龙头。。");
}
public void closeValue(){
System.out.println("正在为您关闭水龙头。。");
}
}
//热水浴缸
class Hottub{
public void circulate(){
System.out.println("已经为您设置循环加热水。。");
}
public void jetsOn(){
System.out.println("已经为您打开喷头。。");
}
public void jetsOff(){
System.out.println("已经为您关闭喷头。。");
}
public void setTemperature(){
System.out.println("正在为您调节适宜水温。。");
}
}
//恒温器
class Thermostat{
public void setTemperature(){
System.out.println("已经为您调好温度。。");
}
}
//安全控制
class SecurityControl{
public void arm(){
}
public void disarm(){
}
}
遥控器是请求者,请求执行如上操作,家电是执行者,执行具体开关等操作,现在把请求命令拿出来封装成对象,所以我们提供一个命令接口Command2,遥控器只管去调命令接口的execute()方法,其他的不管,执行者就是你调我execute()我就执行我的操作,其他不管,请求者遥控器和执行者家电不会直接交互,达到解耦。
2.把命令拿出来封装,提供execute()对外接口,
//公共命令接口-执行命令方法
interface Command2{
public void execute();//执行
public void undo();//撤销
}
//啥也不做命令
class NoCommand2 implements Command2{
public void execute(){
System.out.println("啥也不做命令哦。。");
}
public void undo(){
System.out.println("啥也没撤销。。");
}
}
3.再来实现具体电器的开、关命令
//打开电灯命令
class LightOnCommand2 implements Command2{
Light2 light1;
public LightOnCommand2(Light2 light){//可传所有灯对象
this.light1 = light;
}
public void execute(){
light1.on();
}
public void undo(){
light1.off();
}
}
//关闭电灯命令
class LightOffCommand2 implements Command2{
Light2 light;
public LightOffCommand2(Light2 light){
this.light = light;
}
public void execute(){
light.off();
}
public void undo(){
light.on();
}
}
//打开车库门命令
class GarageDoorOpenCommand implements Command2{
GarageDoor door;
public GarageDoorOpenCommand(GarageDoor door){//不写有参构造还不行,的给door一个new好的对象,不然door.up()会报错 空指针,都没对象呢,调啥方法
this.door = door;
}
public void execute(){
door.up();
}
public void undo(){
door.down();
}
}
class GarageDoorCloseCommand implements Command2{
GarageDoor door;
public GarageDoorCloseCommand(GarageDoor door){
this.door = door;
}
public void execute(){
door.down();
}
public void undo(){
door.up();
}
}
//打开音响同时播放CD命令
class StereoOnWithCDCommand2 implements Command2{
Stereo2 stereo;
public StereoOnWithCDCommand2(Stereo2 stereo){
this.stereo = stereo;
}
public void execute(){
stereo.on();
stereo.setCD();
stereo.setVolume();
}
public void undo(){
stereo.off();
}
}
class StereoCloseWithCDCommand2 implements Command2{
Stereo2 stereo;
public StereoCloseWithCDCommand2(Stereo2 stereo){
this.stereo = stereo;
}
public void execute(){
stereo.off();
}
public void undo(){
stereo.on();
}
}
4.现在就可以实现遥控器了
//按钮固定功能遥控器
class ButtonControl{
Command2[] onCommand2;//给遥控器多个按钮放不同命令,就是一个数组放了好多命令
Command2[] offCommand2;//一个放开命令,一个放关命令
Command2 undoCommand;//这个空命令用作撤销
public ButtonControl(){//构造的时候 给7个插槽分别赋空命令
onCommand2 = new Command2[7];
offCommand2 = new Command2[7];
NoCommand2 noCommand2 = new NoCommand2();
for(int i=0;i<7;i++){//构造的时候,初始化按钮都放空命令
onCommand2[i] = noCommand2;
offCommand2[i] = noCommand2;
}
undoCommand = noCommand2;
}
//给每个按钮放固定命令 slot代表位置 第几个按钮放啥命令的
public void setCommand(int slot,Command2 onCommand,Command2 offCommand){
onCommand2[slot] = onCommand;
offCommand2[slot] = offCommand;
}
public void onButtonPressed(int slot){//按固定位置的按钮
onCommand2[slot].execute();//该位置放的按钮对象就去执行它的execute方法
undoCommand = onCommand2[slot];
}
public void offButtonPressed(int slot){//关按钮 同上
offCommand2[slot].execute();
undoCommand = offCommand2[slot];
}
public void undoButtonPressed(){
undoCommand.undo();
}
public String toString(){
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("\n-----------------有7个按钮的遥控器------------------\n");
for(int i=0;i<onCommand2.length;i++){
stringBuffer.append("[slot"+i+"]"+onCommand2[i].getClass().getName()+" "+offCommand2.getClass().getName()+"\n");
}
return stringBuffer.toString();
}
}
5.现在来简单调试一下
//家电自动化厂商类
public class AutoCompany {
public static void main(String args[]){
SimpleControl control = new SimpleControl();
//打开天花板灯命令
CeilingLight ceiling = new CeilingLight("嘎嘎");//先new电器
LightOnCommand2 lightOn = new LightOnCommand2(ceiling);//这个命令操作哪个电器
control.setCommand(lightOn);//按钮放命令
control.pressedButton();//按按钮
//执行打开车库门命令
GarageDoor door = new GarageDoor();
GarageDoorOpenCommand doorOpen = new GarageDoorOpenCommand(door);
control.setCommand(doorOpen);
control.pressedButton();
//试试7个按钮的插槽吧
ButtonControl buttonControl = new ButtonControl();
CeilingLight ceilingLight = new CeilingLight("天花板灯。。");
GarageDoor door2 = new GarageDoor();
Stereo2 stereo = new Stereo2();
LightOnCommand2 lightOn2 = new LightOnCommand2(ceilingLight);
LightOffCommand2 lightOff2 = new LightOffCommand2(ceilingLight);
GarageDoorOpenCommand openDoor = new GarageDoorOpenCommand(door2);
GarageDoorCloseCommand closeDoor = new GarageDoorCloseCommand(door2);
StereoOnWithCDCommand2 stereoOn = new StereoOnWithCDCommand2(stereo);
StereoCloseWithCDCommand2 stereoOff = new StereoCloseWithCDCommand2(stereo);
buttonControl.setCommand(0, lightOn2, lightOff2);
buttonControl.setCommand(1, openDoor, closeDoor);
buttonControl.setCommand(6, stereoOn, stereoOff);
buttonControl.onButtonPressed(0);
System.out.println(buttonControl);
buttonControl.undoButtonPressed();
buttonControl.onButtonPressed(0);
buttonControl.offButtonPressed(0);
buttonControl.offButtonPressed(1);
buttonControl.onButtonPressed(6);
buttonControl.offButtonPressed(6);
buttonControl.undoButtonPressed();
System.out.println(buttonControl);
//带状态的吊扇
CeilingFan2 ceiling2 = new CeilingFan2("吊扇");
CeilingFanHighCommand hignCommand1 = new CeilingFanHighCommand(ceiling2);
CeilingFanMediumCommand mediumCommand2 = new CeilingFanMediumCommand(ceiling2);
buttonControl.setCommand(5, hignCommand1, mediumCommand2);
buttonControl.onButtonPressed(5);//设置高速
buttonControl.offButtonPressed(5);//设置中速
buttonControl.undoButtonPressed();
System.out.println(buttonControl);
//宏命令-一次执行所有操作测试 这往下不用看啦
CeilingLight light = new CeilingLight("天花板灯。。");
Stereo2 stereo2 = new Stereo2();
GarageDoor door3 = new GarageDoor();
LightOnCommand2 lighton = new LightOnCommand2(light);
LightOffCommand2 lightOff = new LightOffCommand2(light);
StereoOnWithCDCommand2 stereoOn2 = new StereoOnWithCDCommand2(stereo2);
StereoCloseWithCDCommand2 stereClose = new StereoCloseWithCDCommand2(stereo2);
GarageDoorOpenCommand doorOpen2 = new GarageDoorOpenCommand(door3);
GarageDoorCloseCommand doorClose = new GarageDoorCloseCommand(door3);
Command2[] commandOns = {lighton,stereoOn2,doorOpen2};
Command2[] commandCloses = {lightOff,stereClose,doorClose};
//MacroCommand macroOn = new MacroCommand(commandOns);
//MacroCommand macroclose = new MacroCommand(commandCloses);
//buttonControl.setCommand(3, macroOn, macroclose);
System.out.println(buttonControl);
buttonControl.onButtonPressed(3);
buttonControl.offButtonPressed(3);
}
}
6.运行结果
已经为您打开天花板的灯。。
正在为你生起车库门。。
已经为您打开天花板的灯。。
—————–有7个按钮的遥控器——————
[slot0]test.LightOnCommand2 [Ltest.Command2;
[slot1]test.GarageDoorOpenCommand [Ltest.Command2;
[slot2]test.NoCommand2 [Ltest.Command2;
[slot3]test.NoCommand2 [Ltest.Command2;
[slot4]test.NoCommand2 [Ltest.Command2;
[slot5]test.NoCommand2 [Ltest.Command2;
[slot6]test.StereoOnWithCDCommand2 [Ltest.Command2;
已经为您关上天花板的灯。。
已经为您打开天花板的灯。。
已经为您关上天花板的灯。。
正在为您关闭车库门。。
已经为您打开音响。。
已经为您放好CD光盘。。
正在为您调节立体声音量。。
已经为您关闭音响。。
已经为您打开音响。。
—————–有7个按钮的遥控器——————
[slot0]test.LightOnCommand2 [Ltest.Command2;
[slot1]test.GarageDoorOpenCommand [Ltest.Command2;
[slot2]test.NoCommand2 [Ltest.Command2;
[slot3]test.NoCommand2 [Ltest.Command2;
[slot4]test.NoCommand2 [Ltest.Command2;
[slot5]test.NoCommand2 [Ltest.Command2;
[slot6]test.StereoOnWithCDCommand2 [Ltest.Command2;
吊扇 速度现在是高速
吊扇 速度现在是中速
吊扇 速度现在是高速
—————–有7个按钮的遥控器——————
[slot0]test.LightOnCommand2 [Ltest.Command2;
[slot1]test.GarageDoorOpenCommand [Ltest.Command2;
[slot2]test.NoCommand2 [Ltest.Command2;
[slot3]test.NoCommand2 [Ltest.Command2;
[slot4]test.NoCommand2 [Ltest.Command2;
[slot5]test.CeilingFanHighCommand [Ltest.Command2;
[slot6]test.StereoOnWithCDCommand2 [Ltest.Command2;
—————–有7个按钮的遥控器——————
[slot0]test.LightOnCommand2 [Ltest.Command2;
[slot1]test.GarageDoorOpenCommand [Ltest.Command2;
[slot2]test.NoCommand2 [Ltest.Command2;
[slot3]test.NoCommand2 [Ltest.Command2;
[slot4]test.NoCommand2 [Ltest.Command2;
[slot5]test.CeilingFanHighCommand [Ltest.Command2;
[slot6]test.StereoOnWithCDCommand2 [Ltest.Command2;
啥也不做命令哦。。
啥也不做命令哦。。
我的理解是这样滴:
哎呀妈呀,这图 转不过来了,
意思就是说,遥控器要让灯亮,但是让灯亮这个命令单独拿出来封装了,因为命令有很多,又把命令抽象出一接口command,然后遥控器调接口类型对象的执行方法,具体的子类对象命令去执行它重写的execute方法,这是一个多态的体现,
而具体命令对象又做了什么呢,它在构造的时候,也就是初始化的时候加载了灯类型的对象,在execute里就可以去调灯的具体子类什么灯的重写的开关方法,这也是一处多态的体现,
这样遥控器和灯都是和命令对象打交道,他们互相之间并不熟、不认识,达到了请求者和执行者解耦的效果,
这样你在增加什么电器,或者遥控器有什么改动都不会互相影响,可扩展性强。