今天下班客厅的灯确实亮堂了许多,照照镜子感觉自己一下苍老许多,看来还是灯光暗比较好,看不出来自己的憔悴啊,哈哈,其实还是头发长了,决定出去剪发。

       进到美发店,便有热情的服务生招呼,显示洗头,挑选造型师,开始剪发,剪发中被造型师推荐了各种各样的收费项目,我只选择了一样软化头发。完毕之后,看了下单子哇塞、好贵噢,不过造型师给我剪的发型我还是很喜欢的,我决定以后还找他剪,但是又太贵,无奈中,发型师向我推荐了他们的会员卡,全场所有项目均5折,最近因为圣诞节还在搞活动这期间办卡的可享受折上折8.6,我心想那这下就太划算了,而且他们总店,分店都可以用,所以毫不犹豫的办了张会员卡。。。囧。。。。

       到家后稍微有点后悔,我竟然一时冲动花了那么多钱办了张剪发的会员卡,不过办也办了,只好自己安慰安慰自己,心想,办了卡可以打折上折,而且那么多分店想去哪家去哪家,顿时心情好为能好一点了,突然间想到了一个模式,跟现在的场景很合适,名字叫《组合模式》,为什么说跟组合模式很相似呢?

       先看看组合模式的定义吧,在《大话设计模式一书中》组合模式的定义为:“将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

       那就拿我剪发办卡的事情来分析一下吧。

       首先,一张卡可以在总部,分店,×××店使用,那么总部可以刷卡,分店也可以刷卡,×××店也可以刷卡,这个属性结构的店面层级关系就明确啦。

       那么,总店刷卡消费与分店刷卡消费是一样的道理,那么总店与分店对会员卡的使用也具有一致性。

      1.组合模式的例子

        组合模式结构图:

        那么组合模式的实例如下:

 
  1. //抽象的部件类描述将来所有部件共有的行为  
  2.     public abstract class Component  
  3.     {  
  4.         protected string name;  
  5.         public string Name  
  6.         {  
  7.             get 
  8.             {  
  9.                 return name;  
  10.             }  
  11.             set 
  12.             {  
  13.                 name = value;  
  14.             }  
  15.         }  
  16.         //添加部件  
  17.         public abstract void Add(Component component);  
  18.         //删除部件  
  19.         public abstract void Remove(Component component);  
  20.         //遍历所有子部件  
  21.         public abstract void eachChild();  
  22.     }  
  23.  
  24.     //组合部件类  
  25.     public class Leaf : Component  
  26.     {  
  27.         //叶子节点不具备添加的能力,所以不实现  
  28.         public override void Add(Component component)  
  29.         {  
  30.             throw new NotImplementedException();  
  31.         }  
  32.  
  33.         //叶子节点不具备添加的能力必然也不能删除  
  34.         public override void Remove(Component component)  
  35.         {  
  36.             throw new NotImplementedException();  
  37.         }  
  38.  
  39.         //叶子节点没有子节点所以显示自己的执行结果  
  40.         public override void eachChild()  
  41.         {  
  42.             Console.WriteLine("{0}执行了..",name);  
  43.         }  
  44.     }  
  45.  
  46.     //组合类  
  47.     public class Composite : Component  
  48.     {  
  49.         //用来保存组合的部件  
  50.         List<Component> myList = new List<Component>();  
  51.  
  52.         //添加节点 添加部件  
  53.         public override void Add(Component component)  
  54.         {  
  55.             myList.Add(component);  
  56.         }  
  57.  
  58.         //删除节点 删除部件  
  59.         public override void Remove(Component component)  
  60.         {  
  61.             myList.Remove(component);  
  62.         }  
  63.  
  64.         //遍历子节点  
  65.         public override void eachChild()  
  66.         {  
  67.             Console.WriteLine("{0}执行了..", name);  
  68.             foreach (Component c in myList)  
  69.             {  
  70.                 c.eachChild();  
  71.             }  
  72.         }  
  73.     }  
  74.     static void Main(string[] args)  
  75.     {  
  76.             //构造根节点  
  77.             Composite rootComponent = new Composite();  
  78.             rootComponent.Name = "根节点";  
  79.  
  80.             //添加两个叶子几点,也就是子部件  
  81.             Leaf l = new Leaf();  
  82.             l.Name = "叶子节点一";  
  83.             Leaf l1 = new Leaf();  
  84.             l1.Name = "叶子节点二";  
  85.  
  86.             rootComponent.Add(l);  
  87.             rootComponent.Add(l1);  
  88.  
  89.             //遍历组合部件  
  90.             rootComponent.eachChild();  
  91.      } 

        运行结果如下:

     

      2.应用组合模式的会员卡消费

        那么我们就根据我们会员卡的消费,来模拟一下组合模式的实现吧!let's go!

        首先:

               1.我们的部件有,总店,分店,×××店!

               2.我们的部件共有的行为是:刷会员卡

               3.部件之间的层次关系,也就是店面的层次关系是,总店下有分店、分店下可以拥有×××店。

        有了我们这几个必要条件后,我的要求就是目前店面搞活动当我在总店刷卡后,就可以累积相当于在所有下级店面刷卡的积分总额,设计的代码如下:

 
  1. /// <summary>  
  2.     /// 店面类 抽象出来的店面部件  
  3.     /// </summary>  
  4.     public abstract class Storefront  
  5.     {  
  6.         //店名  
  7.         protected string storeName = string.Empty;  
  8.         public string StoreName  
  9.         {  
  10.             get 
  11.             {  
  12.                 return storeName;  
  13.             }  
  14.         }  
  15.  
  16.         //添加店面  
  17.         public abstract void Add(Storefront store);  
  18.         //删除店面  
  19.         public abstract void Remove(Storefront store);  
  20.  
  21.         //定义所有部件公用的行为 刷卡行为  
  22.         public abstract void PayByCard();  
  23.     }  
  24.  
  25.     public class StoreOrBranch : Storefront  
  26.     {  
  27.         //构造函数  
  28.         public StoreOrBranch() { }  
  29.         public StoreOrBranch(string storeName)  
  30.         {  
  31.             this.storeName = storeName;  
  32.         }  
  33.         List<Storefront> myStoreList = new List<Storefront>();  
  34.         //刷卡消费  
  35.         public override void PayByCard()  
  36.         {  
  37.             Console.WriteLine("店面{0}的积分已累加进该会员卡", storeName);  
  38.             foreach (Storefront sf in myStoreList)  
  39.             {  
  40.                 sf.PayByCard();  
  41.             }  
  42.         }  
  43.  
  44.         //增加店面  
  45.         public override void Add(Storefront store)  
  46.         {  
  47.             myStoreList.Add(store);  
  48.         }  
  49.  
  50.         //解除店面  
  51.         public override void Remove(Storefront store)  
  52.         {  
  53.             myStoreList.Remove(store);  
  54.         }  
  55.     }  
  56.  
  57.     public class JoinInStore : Storefront  
  58.     {  
  59.         //构造函数  
  60.         public JoinInStore() { }  
  61.         public JoinInStore(string storeName)  
  62.         {  
  63.             this.storeName = storeName;  
  64.         }  
  65.         //刷卡消费  
  66.         public override void PayByCard()  
  67.         {  
  68.             Console.WriteLine("店面{0}的积分已累加进该会员卡", storeName);  
  69.         }  
  70.  
  71.         public override void Add(Storefront store)  
  72.         {  
  73.             throw new NotImplementedException();  
  74.         }  
  75.  
  76.         public override void Remove(Storefront store)  
  77.         {  
  78.             throw new NotImplementedException();  
  79.         }  
  80.     }  
  81.  
  82.    static void Main(string[] args)  
  83.    {  
  84.             StoreOrBranch store = new StoreOrBranch("朝阳总店");  
  85.             StoreOrBranch brach = new StoreOrBranch("东城分店");  
  86.             JoinInStore jstore = new JoinInStore("海淀×××店一");  
  87.             JoinInStore jstore1 = new JoinInStore("上地×××店二");  
  88.  
  89.             brach.Add(jstore);  
  90.             brach.Add(jstore1);  
  91.             store.Add(brach);  
  92.  
  93.             store.PayByCard();  
  94.     }  
       运行结果如下:

      

       这样在累积所有子店面积分的时候,就不需要去关心子店面的个数了,也不用关系是否是叶子节点还是组合节点了,也就是说不管是总店刷卡,还是×××店刷卡,都可以正确有效的计算出活动积分。

      3.什么情况下使用组合模式

       引用大话设计模式的片段:“当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了。”