1. 程式人生 > 其它 >設計模式之命令模式(Command)

設計模式之命令模式(Command)

一、命令模式的定義

  命令(Command)模式的定義如下:將一個請求封裝為一個物件,使發出請求的責任和執行請求的責任分割開。這樣兩者之間通過命令物件進行溝通,這樣方便將命令物件進行儲存、傳遞、呼叫、增加與管理。

二、命令模式優缺點

  命令模式的主要優點如下:

  • 降低系統的耦合度。命令模式能將呼叫操作的物件與實現該操作的物件解耦。
  • 增加或刪除命令非常方便。採用命令模式增加與刪除命令不會影響其他類,它滿足“開閉原則”,對擴充套件比較靈活。
  • 可以實現巨集命令。命令模式可以與組合模式結合,將多個命令裝配成一個組合命令,即巨集命令。
  • 方便實現 Undo 和 Redo 操作。命令模式可以與後面介紹的備忘錄模式結合,實現命令的撤銷與恢復。

  其缺點是:

  • 可能產生大量具體命令類。因為計對每一個具體操作都需要設計一個具體命令類,這將增加系統的複雜性。

三、命令模式的實現

  可以將系統中的相關操作抽象成命令,使呼叫者與實現者相關分離,命令模式包含以下主要角色:

  • 抽象命令類(Command)角色:宣告執行命令的介面,擁有執行命令的抽象方法 execute()。
  • 具體命令角色(Concrete Command)角色:是抽象命令類的具體實現類,它擁有接收者物件,並通過呼叫接收者的功能來完成命令要執行的操作。
  • 實現者/接收者(Receiver)角色:執行命令功能的相關操作,是具體命令物件業務的真正實現者。
  • 呼叫者/請求者(Invoker)角色:是請求的傳送者,它通常擁有很多的命令物件,並通過訪問命令物件來執行相關請求,它不直接訪問接收者。

  其結構圖如圖所示:

                

  程式碼實現如下:

public class CommandPattern
{
    public static void main(String[] args)
    {
        Command cmd=new ConcreteCommand();
        Invoker ir=new Invoker(cmd);
        System.out.println("客戶訪問呼叫者的call()方法...");
        ir.call();
    }
}
//呼叫者
class Invoker
{
    private Command command;
    public Invoker(Command command)
    {
        this.command=command;
    }
    public void setCommand(Command command)
    {
        this.command=command;
    }
    public void call()
    {
        System.out.println("呼叫者執行命令command...");
        command.execute();
    }
}
//抽象命令
interface Command
{
    public abstract void execute();
}
//具體命令
class ConcreteCommand implements Command
{
    private Receiver receiver;
    ConcreteCommand()
    {
        receiver=new Receiver();
    }
    public void execute()
    {
        receiver.action();
    }
}
//接收者
class Receiver
{
    public void action()
    {
        System.out.println("接收者的action()方法被呼叫...");
    }
}

  執行結果如下:

客戶訪問呼叫者的call()方法...
呼叫者執行命令command...
接收者的action()方法被呼叫...

四、命令模式的應用場景

  命令模式通常適用於以下場景。

  • 當系統需要將請求呼叫者與請求接收者解耦時,命令模式使得呼叫者和接收者不直接互動。
  • 當系統需要隨機請求命令或經常增加或刪除命令時,命令模式比較方便實現這些功能。
  • 當系統需要執行一組操作時,命令模式可以定義巨集命令來實現該功能。
  • 當系統需要支援命令的撤銷(Undo)操作和恢復(Redo)操作時,可以將命令物件儲存起來,採用備忘錄模式來實現。

五、命令模式的擴充套件

  在軟體開發中,有時將命令模式與前面學的組合模式聯合使用,這就構成了巨集命令模式,也叫組合命令模式。巨集命令包含了一組命令,它充當了具體命令與呼叫者的雙重角色,執行它時將遞迴呼叫它所包含的所有命令,其具體結構圖如圖所示:

            

  程式碼如下:

public class CompositeCommandPattern
{
    public static void main(String[] args)
    {
        AbstractCommand cmd1=new ConcreteCommand1();
        AbstractCommand cmd2=new ConcreteCommand2();
        CompositeInvoker ir=new CompositeInvoker();
        ir.add(cmd1);
        ir.add(cmd2);
        System.out.println("客戶訪問呼叫者的execute()方法...");
        ir.execute();
    }
}
//抽象命令
interface AbstractCommand
{
    public abstract void execute();
}
//樹葉構件: 具體命令1
class ConcreteCommand1 implements AbstractCommand
{
    private CompositeReceiver receiver;
    ConcreteCommand1()
    {
        receiver=new CompositeReceiver();
    }
    public void execute()
    {       
        receiver.action1();
    }
}
//樹葉構件: 具體命令2
class ConcreteCommand2 implements AbstractCommand
{
    private CompositeReceiver receiver;
    ConcreteCommand2()
    {
        receiver=new CompositeReceiver();
    }
    public void execute()
    {       
        receiver.action2();
    }
}
//樹枝構件: 呼叫者
class CompositeInvoker implements AbstractCommand
{
    private ArrayList<AbstractCommand> children = new ArrayList<AbstractCommand>();   
    public void add(AbstractCommand c)
    {
        children.add(c);
    }   
    public void remove(AbstractCommand c)
    {
        children.remove(c);
    }   
    public AbstractCommand getChild(int i)
    {
        return children.get(i);
    }   
    public void execute()
    {
        for(Object obj:children)
        {
            ((AbstractCommand)obj).execute();
        }
    }    
}
//接收者
class CompositeReceiver
{
    public void action1()
    {
        System.out.println("接收者的action1()方法被呼叫...");
    }
    public void action2()
    {
        System.out.println("接收者的action2()方法被呼叫...");
    }
}

  測試結果如下:

客戶訪問呼叫者的execute()方法...
接收者的action1()方法被呼叫...
接收者的action2()方法被呼叫...