Command模式屬于行為模式,作為大名鼎鼎的23個(gè)設(shè)計(jì)模式之一,Command模式理解起來(lái)不如工廠模式,單例模式等那么簡(jiǎn)單直白。究其原因,行為模式著重于使用,如果沒(méi)有編程實(shí)踐,確實(shí)不如創(chuàng)造模式那么直白。我們先看看UML類圖。

估計(jì)很多同學(xué)看著圖就暈了,那么多東西,Command和Concrete Command還好理解,那些Receiver和Invoker又是什么東西呢?
別著急,只要理解了一點(diǎn),這個(gè)模式就很容易理解了,下面劃重點(diǎn),Command模式最主要的特點(diǎn),是將命令封裝成類,在類中保存命令執(zhí)行的上下文(即該命令執(zhí)行的參數(shù),執(zhí)行的對(duì)象),以實(shí)現(xiàn)命令執(zhí)行對(duì)象和命令發(fā)出對(duì)象的解耦。
這樣一來(lái)是不是覺(jué)得好理解多了?Command類里面的Receiver,就是命令具體執(zhí)行的對(duì)象。這里的Client可以理解為裝配環(huán)境,在這里面代碼實(shí)例化Command。Invoker內(nèi)部保存命令(可以保存多條命令,實(shí)現(xiàn)命令記錄查看,撤銷等),客戶端代碼通過(guò)Invoker來(lái)操作命令。接下來(lái)我們看看示例代碼。
定義Command接口
首先我們定義一個(gè)支持撤銷的Command接口。
interface Command
{
void Execute();
void Undo();
}
定義Receiver
接下來(lái)我們定義Receiver,也就是命令的執(zhí)行對(duì)象,這里我們定義一個(gè)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);
}
}
定義具體命令
這里定義兩個(gè)命令,一個(gè)修改名字,一個(gè)修改大小。
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
接下來(lái)是Invoker,,也就是存儲(chǔ)命令,并最終會(huì)被用戶代碼調(diào)用的類,這里我們叫它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
}
}
}
使用命令
現(xiàn)在我們看看客戶端代碼是怎么使用他們的,定義Ball,定義命令,通過(guò)CommandManager去調(diào)用,這樣可以方便查看命令記錄,撤銷命令,等。
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();
}
就醬,我們已經(jīng)實(shí)現(xiàn)了命令模式,并且還支持命令的記錄與撤銷,希望能對(duì)大家有點(diǎn)幫助。
|