不一樣的命令模式(設計模式十五)

夢裡小探花發表於2020-09-08

前言

什麼是命令模式呢?其實是這樣一個東西。

“行為請求者”與“行為實現者”通常呈現一種“緊耦合”

先介紹一下什麼是行為請求者和行為實現者沒有分開:

class Person()
{
  public void eat()
  {
      //吃飯
  }
  public void sleep()
  {
      //碎覺
  }
}

class ClientA()
{
   public void do()
  {
     person.eat();
  }
}

這個是行為請求者和行為實現者沒有分開。

他們通過之間呼叫的方式,是一個緊耦合的關係。但是有些情況下,緊耦合並不適用。
現在又一個一個客戶:

class ClientB()
{
   public void do()
  {
     person.sleep();
  }
}

比如說,現在clientA和clientB 非常多,並且是一個併發多執行緒的過程,但是又不立即執行,比如說訂單系統,要保持高響應。

要達到這種目的就需要一個佇列(當然也可以兩個佇列,但是如果person行為非常多,那麼佇列數量多的話難以維護),也就是說要把person.eat()和person.sleep()封裝成一個具備公共介面或者公共父類物件。這就是命令模式的核心思想,把一個行為封裝成一個物件。

把概念貼一下:

命令模式(Command Pattern)是一種資料驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在物件中,並傳給呼叫物件。呼叫物件尋找可以處理該命令的合適的物件,並把該命令傳給相應的物件,該物件執行命令。 

正文

那麼可以這樣寫,下面為手寫,不一定完全正確。

public abstract class Command
{
   public abstract void excute();
}
public class EatCommand:Command
{
   Peason peason;
   public EatCommand(Peason peason)
  {
    this.Person=Person
  }
  public void excute()
  {
    peason.eat();
  }
}
public class SleepCommand:Command
{
   Peason peason;
   public SleepCommand(Peason peason)
  {
    this.Person=Person
  }
  public void excute()
  {
    peason.sleep();
  }
}
public class Manager
{
   private static queue q=new queue();
   public Manager()
   {

   }
   public void add(Command command)
   {
        q.add(command);
   }
   public void excute()
  {
      if(q.Count!=0)
      {
         //不用擔心這樣寫覺得command 會多餘哈,編譯器會幫我們優化,這樣寫更清晰
         var command=q.Dequeue() as Command;
         command.excute();
      }
  }
}

這裡只寫clientA:

class ClientA()
{
   public void do()
  {
     //不要關心person怎麼來的,可以new 一個或者工廠例項化,等等
     EatCommand Eatcomment=new EatCommand(person);
     //manager 單例,在另外一個執行緒中消費
     manager.add(Eatcomment);
  }
}

這樣寫就是將一個行為變成了一個物件,而行為請求者和行為執行者,耦合性降低,這樣靈活性就上升了。

比如說,需要clientA 需要撤銷功能。

public void do()
{
  EatCommand Eatcomment=new EatCommand(person);
  if(...)
  {
    manager.add(Eatcomment);
  }
  if(...)
  {
    manager.remove(Eatcomment);
 }
  manager.excute();
}

我這裡沒有實現remove,如果是這種的話,那麼就不是一個佇列而是一個集合或者別的。

這樣可以自由控制行為,而且可以延遲執行,延遲執行的優點可以參考linq。

因為行為變成了物件,誰是執行者這個問題就弱化了(就是說當person傳給了command,那麼關注點和person就沒有關係了),更多的關係到功能實現上了。

缺點:
使用命令模式可能會導致某些系統有過多的具體命令類。因為針對每一個命令都需要設計一個具體命令類,因此某些系統可能需要大量具體命令類,這將影響命令模式的使用。

相關文章