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  命令也能夠用來實現日誌和事務系統。

相關文章
相關標籤/搜索