首页 > 代码库 > 小故事学设计模式之Command : (一) 在永和豆浆店
小故事学设计模式之Command : (一) 在永和豆浆店
IT的事就是过场多,过场多了就容易忘,所以我们不妨看一个记一个,这也是一个办法,顺便跟同行们学习交流一下)
前几天出去拍照,饿到腿软, 回城附近有一家永和豆浆店, 我们决定去那边解决午餐.
豆浆店里面还不错, 整得挺时尚的, (跟我几年前在杭州去的那家区别蛮大).我喜欢餐馆里明亮的色调和鲜翠欲滴的菜品照片.
服务员也不错, 挺和气的.
邻桌饭菜的香气弥漫开来,像卡通片一样飘过来, 罩着点菜的我们俩和面前可爱的服务员(三个大头娃娃!).
服务员熟练地询问,打字, 然后把小票传给后面厨房的小窗里. 一回头又面对下一位顾客了.
真是职业化! 我赞叹不已.
让我想起软件设计中的command模式.
!永和豆浆店的Command模式!
command模式我也背不下来定义,但是目的我还是知道的, 就是为了让不同的人专心做好自己的事, 以达到高效率完成一个任务的目的.
这里作为客人的我俩, 只专心挑选自己喜欢的饭菜, 其他的我不用操心.
作为服务员, 她只管专心在电脑中录入我们点的菜名, 然后把小票传给厨房, 至于菜里放多少盐,根本也不是她份内的事,所以她也用不着烦心.
而厨子的任务就是按单做菜.(这里我没有写厨子,只是为了简单起见)
用软件的术语讲, 为了达到command模式的目的, 我们要防止类和类之间过于耦合, 让它们之间的消息传递尽量简洁明确.
public interface ICustomer { string Name { get; } }
public class FeiFei:ICustomer { private string _name; public string Name { get{ return _name;} set { _name = value;} } public FeiFei(string n) { _name = n; } } public class Neo:ICustomer { private string _name; public string Name { get{ return _name;} set { _name = value;} } public Neo(string n) { _name = n; } }
public class Waitress { Order _o; public Waitress(Order o) { _o = o; OrderUp(); } private void OrderUp() { StringBuilder sb = new StringBuilder(); foreach(ICustomer c in _o.Customer) { sb.Append(c.Name+" , "); } string mycustomer = sb.ToString(); StringBuilder pc = new StringBuilder(); foreach (String p in _o.Packages) { pc.Append(p+" , "); } string mypackage = pc.ToString(); Console.WriteLine(mycustomer + "You picked " + pc ); Console.WriteLine("Please find a place there, thanks!"); } } public class Order { private IList<string> _packages = new List<string>(); private IList<ICustomer> _customers = new List<ICustomer>(); public IList<string> Packages { get { return _packages; } } public IList<ICustomer> Customers { get { return _customers; } } }
好的, 下面的镜头:
主要演员: neo, feifei, 服务员
情景 : (参见代码中的说明)
[TestFixture] public class PlaceOrder { [Test] public void Place() { ICustomer feifei = new FeiFei("Feifei");//neo进店 ICustomer neo = new FeiFei("Neo");//feifei进店 Order o = new Order();//上菜单 o.Customers.Add(neo); o.Packages.Add("Package A");//neo点了套餐A o.Customers.Add(feifei); o.Packages.Add("Package B");//feifei点了套餐B Waitress w = new Waitress(o); //镜头切换到服务员mm那儿,我们把要点的套餐告诉了她,mm在电脑中录入后,礼貌地让我们找个地方先坐坐(场景详见Waitrees类代码) w.OrderUp();
} }
ok,我们来运行一下, 服务员小姐在打出小票后说:
Neo, Feifei, you picked Package A, Package B, Please find a place there, thanks!
这时你可能在想, 那如果客人有其他需要,希望得到服务员的帮助怎么办?以软件设计的术语来说就是, open for adding, close for modification.
唔... ...有道理, 那我们就在原有的设计上再增加这些服务, 下面我来说明一下:
以客人要求提供下面两项服务为例:
1. 要求服务员帮他们带到满意的座位上去.
2. 要求服务员帮他们指引一下洗手间的位置.
我们要做到,以后任何新的职责增加和减少给这个服务员,都不要老去修改服务员员这个类.(要不,服务员是不是很累, 人家很忙的, 你变来变去的, 人家会弄混掉的.)
所以我们增加了一个接口IService, 并派生出两个类 LeadToToilet和LeadToTable, 以后再有什么其他的新职责, 都从这个接口中以类的形式派生出来.
public interface IService { void Execute(); } public class LeadToToilet:IService { public void Execute() { console.WriteLine("Go along the row of tables, and turn left at the end, there lies the toilet!"); } } public class LeadToTable:IService { public void Execute() { console.WriteLine("You might need a no-smoking area, so come with me please!"); } }
而服务员类中, 我们只要增加一个方法SupplyService()就可以了.
public void SupplyService(IService _s) { _s.Execute(); }
OK, 接下来看一下新的场景:
主要演员: 服务员
情景 : 客人想找一个无烟座位, 服务员带他们过去; 客人又想上洗手间, 服务员亲切地给他指路.
[TestFixture] public class PlaceOrder { [Test] public void Place() { ICustomer feifei = new FeiFei("Feifei");//neo进店 ICustomer neo = new FeiFei("Neo");//feifei进店 Waitress w = new Waitress(o); //服务员mm来了 IService WhereShallWeSit = new LeadToTable(); //坐哪里呢 w.SupplyService(WhereShallWeSit);//服务员给我们指导座位 IService WhereIsToilet = new LeadToToilet(); //要上洗手间了 w.SupplyService(WhereIsToilet);//服务员带我过去 } }
执行这段代码, 让我们听听服务员小姐亲切的声音和职业化的素质吧:
You might need a no-smoking area, so come with me please! Go along the row of tables, and turn left at the end, there lies the toilet!
完