前言
什麼是命令模式呢?其實是這樣一個東西。
“行為請求者”與“行為實現者”通常呈現一種“緊耦合”
先介紹一下什麼是行為請求者和行為實現者沒有分開:
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就沒有關係了),更多的關係到功能實現上了。
缺點:
使用命令模式可能會導致某些系統有過多的具體命令類。因為針對每一個命令都需要設計一個具體命令類,因此某些系統可能需要大量具體命令類,這將影響命令模式的使用。