#命令模式(Command Pattern)
##簡介
在面向對象程式設計的范疇中,命令模式是一種設計模式,它嘗試以物件來代表實際行動。命令物件可以把行動(action) 及其參數封裝起來,于是這些行動可以被:
* 重復多次
* 取消(如果該物件有實作的話)
* 取消后又再重做
這些都是現代大型應用程序所必須的功能,即“復原”及“重復”。除此之外,可以用命令模式來實作的功能例子還有:
* 交易行為
* 進度列
* 精靈
* 使用者界面按鈕及功能表項目
* 執行緒 pool
* 宏收錄

JavaScript
```
/* The Invoker function */
var Switch = function(){
var _commands = [];
this.storeAndExecute = function(command){
_commands.push(command);
command.execute();
}
}
/* The Receiver function */
var Light = function(){
this.turnOn = function(){ console.log ('turn on')};
this.turnOff = function(){ console.log ('turn off') };
}
/* The Command for turning on the light - ConcreteCommand #1 */
var FlipUpCommand = function(light){
this.execute = light.turnOn;
}
/* The Command for turning off the light - ConcreteCommand #2 */
var FlipDownCommand = function(light){
this.execute = light.turnOff;
}
var light = new Light();
var switchUp = new FlipUpCommand(light);
var switchDown = new FlipDownCommand(light);
var s = new Switch();
s.storeAndExecute(switchUp);
s.storeAndExecute(switchDown);
```
Java
```
import java.util.List;
import java.util.ArrayList;
/* The Command interface */
public interface Command {
void execute();
}
/* The Invoker class */
public class Switch {
private List<Command> history = new ArrayList<Command>();
public Switch() {
}
public void storeAndExecute(Command cmd) {
this.history.add(cmd); // optional
cmd.execute();
}
}
/* The Receiver class */
public class Light {
public Light() {
}
public void turnOn() {
System.out.println("The light is on");
}
public void turnOff() {
System.out.println("The light is off");
}
}
/* The Command for turning on the light - ConcreteCommand #1 */
public class FlipUpCommand implements Command {
private Light theLight;
public FlipUpCommand(Light light) {
this.theLight = light;
}
public void execute(){
theLight.turnOn();
}
}
/* The Command for turning off the light - ConcreteCommand #2 */
public class FlipDownCommand implements Command {
private Light theLight;
public FlipDownCommand(Light light) {
this.theLight = light;
}
public void execute() {
theLight.turnOff();
}
}
/* The test class or client */
public class PressSwitch {
public static void main(String[] args){
Light lamp = new Light();
Command switchUp = new FlipUpCommand(lamp);
Command switchDown = new FlipDownCommand(lamp);
Switch mySwitch = new Switch();
try {
if ("ON".equalsIgnoreCase(args[0])) {
mySwitch.storeAndExecute(switchUp);
}
else if ("OFF".equalsIgnoreCase(args[0])) {
mySwitch.storeAndExecute(switchDown);
}
else {
System.out.println("Argument \"ON\" or \"OFF\" is required.");
}
} catch (Exception e) {
System.out.println("Arguments required.");
}
}
}
```
##實例
###模擬燒烤
####緊耦合設計
```
//烤肉串者
public class Barbecuer
{
//烤羊肉
public void BakeMutton()
{
Console.WriteMutton("烤羊肉串");
}
//烤雞翅
public void BakeChikenWing()
{
Console.WriteMutton("烤雞翅");
}
}
```
客戶端調用
```
static void Main(string[] args)
{
Barbecuer boy = new Barbecuew();
boy.BakeMutton();
boy.BakeMutton();
boy.BakeMutton();
boy.BakeChickenWing();
}
```
####松耦合設計
抽象命令類
```
//抽象命令
public abstract class Command
{
protected Barbecuer receiver;
public Command(Barbecuer receiver)
{
this.receiver = receiver;
}
//執行命令
abstract public ExcuteCommand();
}
```
具體命令類
```
//烤羊肉命令
class BakeMuttonCommand: Command
{
public BakeMuttonCommand(Barbecuer receiver)
{
:base(receiver)
}
public override void EccuteCommand()
{
receiver.BakeMutton();
}
}
//烤雞翅命令
class BakeMuttonCommand: Command
{
public BakeMuttonCommand(Barbecuer receiver)
{
:base(receiver)
}
public override void EccuteCommand()
{
receiver.BakeChickenWing();
}
}
```
服務員類
```
//服務員
public class Waiter
{
private Command command;
//設置訂單
public void setOrder(Command command)
{
this.command
}
//通知執行
public void Notify()
{
command.ExcuteCommand();
}
}
```
```
//烤肉串者
public class Barbecuer
{
//烤羊肉
public void BakeMutton()
{
Console.WriteMutton("烤羊肉串");
}
//烤雞翅
public void BakeChikenWing()
{
Console.WriteMutton("烤雞翅");
}
}
```
客戶端實現
```
static void Main(string[] args)
{
//開店前的準備
Barbecuer boy = new Barbecuer();
Command BakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command BakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command BakeChickenWingCommand1 = new BakeMuttonCommand(boy);
Waiter girl = new Waiter();
//開門營業
girl.SetOrder(BakeMuttonCommand1);
girl.Notify();
girl.SetOrder(BakeMuttonCommand2);
girl.Notify();
girl.SetOrder(BakeChickenWingCommand1);
girl.Notify();
COnsole.Read();
}
```
####松耦合后
```
//服務員
public class Waiter
{
private IList<Command> orders = new List<Command>();
//設置訂單
public void SetOrder(Command command)
{
if (command.ToString() == "命令模式.BakeChikenWingCommand")
{
Console.WriteLine("服務員:雞翅沒有了,請點別的燒烤。");
}
else
{
orders.Add(command);
Console.WriteLine("增加訂單:"+ command.ToString() + "時間" + DateTime.Now.ToString());
}
}
//取消訂單
public void CancelOrder(Command command)
{
orders.Remove(command);
Console.WriteLine("取消訂單" + command.ToString() + "時間" + DateTime.Now.ToString());
}
//通知全部執行
public void Notify()
{
foreach(Command cmd in orders)
{
cmd.ExcuteCommand();
}
}
}
```
客戶端代碼實現
```
static void Main(string[] args)
{
Barbecuer boy = new Barbecuer();
Command BakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command BakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command BakeChickenWingCommand1 = new BakeMuttonCommand(boy);
Waiter girl = new Waiter();
girl.setOrder(bakeMuttonCommand1);
girl.setOrder(bakeMuttonCommand1);
girl.setOrder(BakeChickenWingCommand1);
girl.Notify();
Console.Read();
}
```
***命令模式:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數話;對請求排隊或者紀錄請求日志,以及支持可撤銷的操作。***
命令模式的優點:
* 容易地設計一個命令隊列。
* 在需求的情況下,比較容易地將命令記入日志。
* 允許接受請求的一方決定是否要回絕請求。
* 很容易對請求撤銷或者重做。
* 加入新的命令類不影響其它的類。
* 把請求一個操作的對象與知道怎么執行一個操作的對象分割開。