设计模式随笔-锦囊妙计 (转)
吕震宇
话说《三国演义》中,周瑜与孙权定下计谋,以孙权之妹为诱饵,骗刘备过江到东吴招亲,想趁机杀害刘备,索回荆州。诸葛亮早识破了诡计,令武将赵云随同并护卫刘备前往,并给赵云了三个锦囊,嘱咐他依次执行即可。结果,赵云按照诸葛亮的锦囊妙计行事,不仅帮助刘备将孙权之妹孙尚香夫人迎娶回来,还得到孙权之母吴国太的欢心,陪同刘备夫妇回了荆州。《三国演义》这段记叙,为后世创造了“锦囊妙计”和“赔了夫人又折兵”两个成语。
今天,我就“锦囊妙计”来说说Command模式。从面向对象的设计角度来说,锦囊妙计有以下几个特色:
1、妙计被装入锦囊后都变得一般模样,没有任何区别。
2、锦囊妙计自己是无法实施的,必须由某个人依计行事。
3、实施者有权利选择执行命令或不执行命令,也可以选择在什么时候执行。当然,在我们的故事中,赵云在合适的时间执行了合适的妙计,便为我们留下了精彩的故事。
这个故事用代码书写出来如下:
using System;
using System.Collections;
abstract class JinNang
{
public string message = "";
public void Execute()
{
Console.WriteLine(message);
}
}
class JinNang1 : JinNang
{
public JinNang1()
{
this.message = "ToDo:让刘备拜见岳艾乔国老,并大造声势。";
}
}
class JinNang2 : JinNang
{
public JinNang2()
{
this.message = "ToDo:假报刘备:曹操起兵五十万,杀奔荆州。";
}
}
class JinNang3: JinNang
{
public JinNang3()
{
this.message = "ToDo:向孙夫人揭穿了孙权和周瑜的阴谋,请求夫人保护。";
}
}
abstract class Receiver
{
protected Queue commands = new Queue();
public void SetCommand(JinNang c)
{
commands.Enqueue(c);
}
protected JinNang GetCommand()
{
if (this.commands.Count != 0)
{
JinNang c = (JinNang)this.commands.Dequeue();
return c;
}
else
return null;
}
public bool FulfilCommand(JinNang c)
{
if(c != null)
{
c.Execute();
return true;
}
else
{
Console.WriteLine("惨了!无计可施了!");
return false;
}
}
abstract public void DoComplexJob();
}
class Zhaoyun : Receiver
{
public override void DoComplexJob()
{
Console.WriteLine("护送刘备去东吴");
Console.WriteLine("到达市徐");
if(!FulfilCommand(GetCommand())) return;
Console.WriteLine("刘备娶了孙权之妹");
Console.WriteLine("发现刘备全不想回荆州");
if(!FulfilCommand(GetCommand())) return;
Console.WriteLine("被孙权追杀");
if(!FulfilCommand(GetCommand())) return;
Console.WriteLine("安然护送刘备抵达荆州,任务完成!");
}
}
class ZhuGeLiang
{
public void JinNangMiaoJi(Receiver r)
{
r.SetCommand(new JinNang1());
r.SetCommand(new JinNang2());
r.SetCommand(new JinNang3());
}
}
public class Client
{
public static void Main( string[] args )
{
Receiver r = new Zhaoyun();
ZhuGeLiang z = new ZhuGeLiang();
z.JinNangMiaoJi(r);
r.DoComplexJob();
}
}
using System.Collections;
abstract class JinNang
{
public string message = "";
public void Execute()
{
Console.WriteLine(message);
}
}
class JinNang1 : JinNang
{
public JinNang1()
{
this.message = "ToDo:让刘备拜见岳艾乔国老,并大造声势。";
}
}
class JinNang2 : JinNang
{
public JinNang2()
{
this.message = "ToDo:假报刘备:曹操起兵五十万,杀奔荆州。";
}
}
class JinNang3: JinNang
{
public JinNang3()
{
this.message = "ToDo:向孙夫人揭穿了孙权和周瑜的阴谋,请求夫人保护。";
}
}
abstract class Receiver
{
protected Queue commands = new Queue();
public void SetCommand(JinNang c)
{
commands.Enqueue(c);
}
protected JinNang GetCommand()
{
if (this.commands.Count != 0)
{
JinNang c = (JinNang)this.commands.Dequeue();
return c;
}
else
return null;
}
public bool FulfilCommand(JinNang c)
{
if(c != null)
{
c.Execute();
return true;
}
else
{
Console.WriteLine("惨了!无计可施了!");
return false;
}
}
abstract public void DoComplexJob();
}
class Zhaoyun : Receiver
{
public override void DoComplexJob()
{
Console.WriteLine("护送刘备去东吴");
Console.WriteLine("到达市徐");
if(!FulfilCommand(GetCommand())) return;
Console.WriteLine("刘备娶了孙权之妹");
Console.WriteLine("发现刘备全不想回荆州");
if(!FulfilCommand(GetCommand())) return;
Console.WriteLine("被孙权追杀");
if(!FulfilCommand(GetCommand())) return;
Console.WriteLine("安然护送刘备抵达荆州,任务完成!");
}
}
class ZhuGeLiang
{
public void JinNangMiaoJi(Receiver r)
{
r.SetCommand(new JinNang1());
r.SetCommand(new JinNang2());
r.SetCommand(new JinNang3());
}
}
public class Client
{
public static void Main( string[] args )
{
Receiver r = new Zhaoyun();
ZhuGeLiang z = new ZhuGeLiang();
z.JinNangMiaoJi(r);
r.DoComplexJob();
}
}
“命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象”。通过将妙计封装成锦囊妙计,便成为可委派的妙计。由一个对象(ZhuGeLiang)创建并封装,然后传递给另一个对象(ZhaoYun),命令在此没有被立即执行,而是Enqueue了。当条件合适的时候,再将命令解开执行。另外,所有的锦囊妙计都有一个共同的特性,就是可以被执行。所以,赵云不用关心这个锦囊与那个锦囊有什么区别,只需执行便是了。
该例子仅仅取了一个Command模式的“意”,丢弃了Command模式的形。设计模式的应用无需过于死板。如果对Command模式感兴趣,可以访问《设计模式(18)-Command Pattern》