Head First 设计模式之命令模式(CommandPattern)

前言:

     本章会将封装带入到一个全新的境界,把方法调用封装起来。经过封装方法调用,把运算块包装成形。调用此运算的对象不须要知道事情是如何进行的,只要知道如何使用包装造成的方法来完成它就ok了。编程

1 现实场景应用

如今有一个遥控器,该遥控器有7个插槽须要编程,能够在每一个插槽上放上不一样的装置,而后用按钮控制它,这七个插槽具有各自的“开”“关”按钮,还有一个总体用的撤销按钮,会撤销最后一个按钮的动做。数组

1.1 建立第一个命令对象

1.1.1 定义命令接口

 

public interfaceCommand
    {
        void Execute();
    }

 

1.1.2 实现一个打开灯的命令

 

publicclass Light //电灯类
    {
        public void On()
        {
            System.Console.WriteLine("Light  is On !");
        }
        public void Off()
        {
            System.Console.WriteLine("Light is Off !");
        }
}
    public class LightOnCommand : Command//实现开灯命令
    {
        private Light light;
        public LightOnCommand(Light light)
        {
            this.light = light;
        }
        public void Execute()
        {
            light.On();
        }      
    }

 

1.1.3 使用命令对象

 

public class LightControl
    {
        privateCommand soft;
        publicvoid SetCommand(Command cmd)
        {
            soft= cmd;//设置命令对象
        }
        publicvoid ButtonWasPressed()
        {
           soft.Execute();//调用命令对象的方法
        }
}

 

1.1.4 简单测试

 

LightControl lightControl = new LightControl();//模拟命令的调用者
Lightlight = new Light();//建立一个电灯对象,做为命令的接收者
LightOnCommand lightOnCommand = new LightOnCommand(light);//建立一个命令,并将接受者传递给它
lightControl.SetCommand(lightOnCommand);//将命令传给调用者
lightControl.ButtonWasPressed();//模拟触发按钮

 

1.2 实现遥控器

 

public class RemoteControl
    {
        Command[] onCommands;//定义打开的命令数组
        Command[] offCommands; //定义关闭的命令数组
        public RemoteControl()
        {
            onCommands = new Command[7];
            offCommands = new Command[7];
            Command noCommand = newNoCommand();
            for (int i = 0; i < 7; i++)
            {
                onCommands[i] = noCommand;//初始化命令数组(默认设置为无命令)
                offCommands[i] = noCommand;
            }
        }
        //将命令设置到对应的控制器
        public void SetCommand(int index,Command onCommand, Command offCommand)
        {
            onCommands[index] = onCommand;
            offCommands[index] = offCommand;
        }
        //触发打开控制器
        public void OnButtonWasPressed(int index)
        {
            onCommands[index].Execute();
        }
        //触发关闭控制器
        public void OffButtonWasPressed(intindex)
        {
            offCommands[index].Execute();
        }
        public override string ToString()
        {
            StringBuilder str = newStringBuilder();
            str.Append("\n------RemoteControl ------\n");
            for (int i = 0; i <onCommands.Length; i++)
            {
                str.Append("[solt" +i + "]" + onCommands[i].GetType().FullName + "      " +offCommands[i].GetType().FullName + "\n");
            }
            return str.ToString();
        }
    }

 

 

1.3 实现其余控制器

 

 //关闭电灯命令
   public classLightOffCommand : Command
    {
        privateLight light;
        publicLightOffCommand(Light light)
        {
           this.light = light;
        }
        publicvoid Execute()
        {
           light.Off();
        }
        publicvoid Undo()
        {
           light.On();
        }
}
//打开电扇命令
public class CeilingFanOnCommand : Command
    {
       CeilingFan ceilingFan;
        intpreSpeed;
        publicCeilingFanOnCommand(CeilingFan ceilingFan)
        {
           this.ceilingFan = ceilingFan;
        }
        publicvoid Execute()
        {
           ceilingFan.On();
        }
        publicvoid Undo()
        {
           ceilingFan.Off();
        }
    }
 //关闭电扇命令
    public classCeilingFanOffCommand : Command
    {
       CeilingFan ceilingFan;
        publicCeilingFanOffCommand(CeilingFan ceilingFan)
        {
           this.ceilingFan = ceilingFan;
        }
        publicvoid Execute()
        {
           ceilingFan.Off();
        }
        publicvoid Undo()
        {
           ceilingFan.On();
        }
    }
//打开车库门命令
    public classGarageDoorOnCommand : Command
    {
       GarageDoor garageDoor;
        publicGarageDoorOnCommand(GarageDoor garageDoor)
        {
            this.garageDoor= garageDoor;
        }
        publicvoid Execute()
        {
           garageDoor.On();
        }
        publicvoid Undo()
        {
           garageDoor.Off();
        }
    }
//关闭车库门命令
    public classGarageDoorOffCommand : Command
    {
       GarageDoor garageDoor;
        publicGarageDoorOffCommand(GarageDoor garageDoor)
        {
           this.garageDoor = garageDoor;
        }
        publicvoid Execute()
        {
            garageDoor.Off();
        }
        publicvoid Undo()
        {
           garageDoor.On();
        }
    }
//打开CD命令
    public classStereCDOnCommand : Command
    {
        StereCDstereCD;
        publicStereCDOnCommand(StereCD stereCD)
        {
           this.stereCD = stereCD;
        }
 
        publicvoid Execute()
        {
           stereCD.On();
        }
        publicvoid Undo()
        {
           stereCD.Off();
        }
    }
//关闭CD命令
    public classStereCDOffCommand : Command
    {
        StereCDstereCD;
        publicStereCDOffCommand(StereCD stereCD)
        {
           this.stereCD = stereCD;
        }
        publicvoid Execute()
        {
           stereCD.Off();
        }
        publicvoid Undo()
        {
           stereCD.On();
        }
    }

 

1.4简单测试

 

RemoteControlremoteControl = new RemoteControl ();
            CeilingFan ceilingFan = newCeilingFan("Living Room");//建立电扇对象
            GarageDoor garageDoor = newGarageDoor();//建立车库门对象
            StereCD stereCD = new StereCD();//建立CD对象
Light light = new Light();//建立电灯对象
            LightOnCommand lightOnCommand = newLightOnCommand(light);//建立开灯命令
            LightOffCommand lightOffCommand =new LightOffCommand(light); //建立关灯命令
CeilingFanOnCommandceilingFanOn = new CeilingFanOnCommand(ceilingFan); //建立开电扇命令
            CeilingFanOffCommand ceilingFanOff= new CeilingFanOffCommand(ceilingFan);//建立关电扇命令
            GarageDoorOnCommand garageDoorOn =new GarageDoorOnCommand(garageDoor);//建立打开电扇命令
            GarageDoorOffCommand garageDoorOff= new GarageDoorOffCommand(garageDoor);//建立关闭电扇命令
            StereCDOnCommand stereCDOn = newStereCDOnCommand(stereCD);//建立打开CD命令
            StereCDOffCommand stereCDOff = newStereCDOffCommand(stereCD);//建立关闭CD命令
            remoteControl.SetCommand(0,lightOnCommand, lightOffCommand);//将电灯命令设置到对应的控制器上
            remoteControl.SetCommand(1,ceilingFanOn, ceilingFanOff); //将电灯命令设置到对应的控制器上
            remoteControl.SetCommand(2,garageDoorOn, garageDoorOff); //将车库门命令设置到对应的控制器上
            remoteControl.SetCommand(3,stereCDOn, stereCDOff); //将CD命令设置到对应的控制器上
  remoteControl.OnButtonWasPressed(0);
           remoteControl.OffButtonWasPressed(0);
           remoteControl.OnButtonWasPressed(1);
           remoteControl.OffButtonWasPressed(1);
           remoteControl.OnButtonWasPressed(2);
           remoteControl.OffButtonWasPressed(2);
           remoteControl.OnButtonWasPressed(3);
           remoteControl.OffButtonWasPressed(3);

 

 

1.5 实现撤销命令

1.5.1 修改命令接口,新增Undo()方法

 

public interfaceCommand
    {
        void Execute();
        void Undo();//新增撤销方法
}

 

1.5.2 修改命令,实现Undo方法

 

public class LightOnCommand : Command
    {
        private Light light;
        public LightOnCommand(Light light)
        {
            this.light = light;
        }
        public void Execute()
        {
            light.On();
        }
        public void Undo()//实现Undo方法
        {
            light.Off(); 
        }
}

 

 

其余类都依次修改数据结构

1.5.3 修改RemoteControl类,新增Command对象记录上一步操做

 

public class RemoteControlWithUndo
    {
       Command[] onCommands;
       Command[] offCommands;
        CommandundoCommand;//建立Command对象用来记录上一步执行的命令
        publicRemoteControlWithUndo()
        {
           onCommands = new Command[7];
           offCommands = new Command[7];
           Command noCommand = new NoCommand();
            for(int i = 0; i < 7; i++)
            {
               onCommands[i] = noCommand;
               offCommands[i] = noCommand;
            }
           undoCommand = noCommand;
        }
………
……..
        publicvoid OnButtonWasPressed(int index)
        {
           onCommands[index].Execute();
           undoCommand = onCommands[index];//记录打开命令
        }
        publicvoid OffButtonWasPressed(int index)
        {
           offCommands[index].Execute();
           undoCommand = offCommands[index];//记录关闭命令
        }
        publicvoid UndoButtonWasPressed()//执行撤销
        {
           undoCommand.Undo();
        }
       ……
       ……       
    }

 

1.6 宏命令

让遥控器具备Party模式,即一个按键可以同步调用多个命令,这就是所谓的宏命令。ide

  

 public class MacroCommand : Command
    {
        Command[] commands;//定义命令数组,用来接收传入的命令
        public MacroCommand(Command[] commands)
        {
            this.commands = commands;
        }
        public void Execute()//批量处理多个命令(即初始化的时候传入的命令数组)
        {
            for (int i = 0; i <commands.Length; i++)
                commands[i].Execute();
        }
        public void Undo()
        {
            for (int i = 0; i <commands.Length; i++)
                commands[i].Undo();
        }
    }

 

 

2 定义命令模式

命令模式将“请求”封装成对象,以便使用不一样的请求、队列或者日志来参数化其余对象。命令模式也支持可撤销的操做。测试

定义命令模式类图:ui

 

3 命令模式的更多用途

3.1 队列请求

命令将运算块打包,而后将它传来传去,即便在命令对象建立许久以后,运算依然能够被调用,甚至能够在不一样的线程中被调用,咱们能够利用这样的特性衍生一下应用,好比:平常安排、线程池、工做队列等。this

工做队列类和进行计算的对象之间彻底是解耦的。它们只要是实现命令模式的对象就能够放到队列里边,当线程可用时就调用此对象的Execute()方法。线程

3.2 日志请求

  某些应用须要咱们将全部动做记录到日志中,并在系统死机以后,从新调用这些动做恢复到以前的状态,命令模式就可以支持这一点。日志

  有许多调用大型数据结构的动做应用没法再每次改变发生时被快速的存储,经过使用记录日志,咱们能够将上次检查点以后的全部操做记录下来,若是系统出现情况,能够从检查点开始应用这些操做。对于更高级的应用而言,这些技巧能够被扩展应用到事务处理中,即一整群操做必须所有完成,或者没有进行任何操做。code

3       总结

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

l  被解耦的二者之间是经过命令对象进行沟通的,命令对象封装了接收者和一个或一组动做。

l  调用者经过调用命令对象的Execute()发出请求,会使得接收者的动做被调用。

l  调用者能够接收命令当作参数,甚至在运行时动态进行。

l  命令能够支持撤销,作法是实现一个undo()方法来回到Execute()被执行以前的状态。

l  宏命令是命令的一种简单的延伸,容许调用多个命令,宏方法也能够支持撤销。

l  命令也能够用来实现日志和事务系统。

相关文章
相关标签/搜索