首页 > 代码库 > 小故事学设计模式之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!