Command模式屬於行為模式,作為大名鼎鼎的23個設計模式之一,Command模式理解起來不如工廠模式,單例模式等那麼簡單直白。究其原因,行為模式著重於使用,如果沒有編程實踐,確實不如創造模式那麼直白。我們先看看UML類圖。 估計很多同學看著圖就暈了,那麼多東西,Command和Concrete ...
Command模式屬於行為模式,作為大名鼎鼎的23個設計模式之一,Command模式理解起來不如工廠模式,單例模式等那麼簡單直白。究其原因,行為模式著重於使用,如果沒有編程實踐,確實不如創造模式那麼直白。我們先看看UML類圖。
估計很多同學看著圖就暈了,那麼多東西,Command和Concrete Command還好理解,那些Receiver和Invoker又是什麼東西呢?
彆著急,只要理解了一點,這個模式就很容易理解了,下麵劃重點,Command模式最主要的特點,是將命令封裝成類,在類中保存命令執行的上下文(即該命令執行的參數,執行的對象),以實現命令執行對象和命令發出對象的解耦。
這樣一來是不是覺得好理解多了?Command類裡面的Receiver,就是命令具體執行的對象。這裡的Client可以理解為裝配環境,在這裡面代碼實例化Command。Invoker內部保存命令(可以保存多條命令,實現命令記錄查看,撤銷等),客戶端代碼通過Invoker來操作命令。接下來我們看看示例代碼。
定義Command介面
首先我們定義一個支持撤銷的Command介面。
interface Command
{
void Execute();
void Undo();
}
定義Receiver
接下來我們定義Receiver,也就是命令的執行對象,這裡我們定義一個Ball類。
class Ball
{
public int Size { get; set; } = 10;
public string Name { get; set; } = "My First Ball";
public void Inspect()
{
Console.WriteLine("My Name is {0} and size is {1}", Name, Size);
}
}
定義具體命令
這裡定義兩個命令,一個修改名字,一個修改大小。
class ChangeNameCommand : Command
{
private Ball _Ball;
private string _OldName;
public string NameYouWant { get; set; }
public ChangeNameCommand(Ball ball)
{
_Ball = ball;
}
public void Execute()
{
_OldName = _Ball.Name;
_Ball.Name = NameYouWant;
}
public void Undo()
{
_Ball.Name = _OldName;
}
}
class ChangeSizeCommand : Command
{
//代碼大同小異,略
}
定義Invoker
接下來是Invoker,,也就是存儲命令,並最終會被用戶代碼調用的類,這裡我們叫它CommandManager。
class CommandManager
{
private Stack<Command> commands = new Stack<Command>();
public void RunCommand(Command command)
{
command.Execute();
commands.Push(command);
}
public void Undo()
{
if (commands.Count > 0)
{
var command = commands.Pop();
command.Undo();
}
}
public void ShowCommands()
{
var temp = commands.Reverse();
foreach(var command in temp)
{
//display command
}
}
}
使用命令
現在我們看看客戶端代碼是怎麼使用他們的,定義Ball,定義命令,通過CommandManager去調用,這樣可以方便查看命令記錄,撤銷命令,等。
static void Main(string[] args)
{
Ball ball = new Ball();
ball.Inspect();
ChangeNameCommand changeName = new ChangeNameCommand(ball) { NameYouWant = "Changed" };
ChangeSizeCommand changeSize = new ChangeSizeCommand(ball) { SizeYouWant = 20 };
CommandManager manager = new CommandManager();
manager.RunCommand(changeName);
manager.RunCommand(changeSize);
ball.Inspect();
manager.ShowCommands();
manager.Undo();
ball.Inspect();
manager.Undo();
ball.Inspect();
}
就醬,我們已經實現了命令模式,並且還支持命令的記錄與撤銷,希望能對大家有點幫助。