设计模式之组合模式

本文通过一个树形结构的例子详细解析了组合模式的原理及其应用。展示了如何通过组合模式将对象组合成树形结构,并实现了对象和对象容器的一致性操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Composite 组合模式主要是应对这 样的问题:一类具有“容器特征”的对象——即他们在充当对象的同时,又是其他对象的容器的情况。在编写时我们常常会造成:客户代码过多地依赖于对象容器复 杂的内部实现,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性的弊端。

        GoF 《设计模式》中说到:将对象组合成树形结构以表示“部分 - 整体”的层次结构。 Composite 模式使得客户对单个对象和组合对象的使用具有一致性。

        Composite 组合模式结构如下:

 



       
说道这,我觉得有一个编程中常见的场景,就是对于树的实现,很符合这个模式。下面我就用这个例子作一下。

        首先,我们先分析对于一棵树所包含的部分,树干、树枝、树叶,其中树干可以看成一个树枝(就是粗了点)。那么我们就应该有两种类实现 Leaf (树叶)和 Limb (树枝)。对于叶子节点和枝节点的不同在于枝节点有子树,而叶子节点没有子树。为了使单个对象和组合对象的使用具有一致性,我可以将叶子节点想象成没有子树的枝节点。这样我就可以得到一个抽象类,代码如下:

        public  abstract  class  AbstractClass

     {

         public  string  name;

         public  ArrayList list;

         public  abstract  void  Add(AbstractClass item);        // 增加一个子节点

         public  abstract  void  Remove(AbstractClass item);     // 去掉一个子节点

         public  abstract  string  Print();                      // 打印当前节点

     }

        然后,我在对叶子节点和枝节点作不同的实现:

        枝节点:

        public  class  Limb:AbstractClass

     {

         public  Limb()

         {

             list = new  ArrayList();

         }

 

         public  override  void  Add(AbstractClass item)

         {

             list.Add(item);

         }

 

         public  override  void  Remove(AbstractClass item)

         {

             if (list.Contains(item))

                 list.Remove(item);

         }

         public  override  string  Print()

         {

             Console.Write(name + "\n" );

             if (list.Count != 0)

             {

                 for (int  i = 0;i<list.Count;i++)

                 {

                     Console.Write("(Parent is "  + name + ")" );

                     ((AbstractClass)list[i]).Print();

                 }

             }

             return  name;

         }

 

     }

     叶子节点:

     public  class  Leaf:AbstractClass

     {

         public  Leaf()

         {

             list = null ;

         }

 

         public  override  void  Add(AbstractClass item)

         {

 

         }

         public  override  void  Remove(AbstractClass item)

         {

           

         }

         public  override  string  Print()

         {

             Console.Write(name + "," );

             return  this .name;

         }

     }

     对于叶子节点来说,不需要子节点,当然也就不需要添加和删除子节点的方法。

     好,接下来,我们可以在客户程序中组建一棵树,来测试一下:

         static  void  Main(string [] args)

         {

             AbstractClass Tree = new  Limb();

             GetTree(Tree);

             PrintTree(Tree);

             Console.Read();

         }

 

          public  static  void  GetTree(AbstractClass Tree)

         {

             Tree.name = "1" ;

             AbstractClass leaf2 = new  Leaf();

             leaf2.name = "2" ;

             Tree.Add(leaf2);

             AbstractClass limb3 = new  Limb();

             limb3.name = "3" ;

             Tree.Add(limb3);

             AbstractClass leaf4 = new  Leaf();

             leaf4.name = "4" ;

             limb3.Add(leaf4);

             AbstractClass leaf5 = new  Leaf();

             leaf5.name = "5" ;

             limb3.Add(leaf5);

         }

 

         public  static  void  PrintTree(AbstractClass Tree)

         {

             Tree.Print();

         }

     输出结果如下:

1

(Parent is 1)2,(Parent is 1)3

(Parent is 3)4,(Parent is 3)5,

在组织这个树时,的确能感觉到 GoF 《设计模式》中的那句话: 单个对象和组合对象的使用具有一致性。当然也的确感觉到一点矛盾:对于叶子节点来说,不需要 ArrayListAdd () Remove ()应该不继承才对,当然如果在代码执行性能可以达到要求的情况下,简化一下编码实现复杂度也是挺好的一件事。

最后在来说说 Composite 组合模式的几个要点:

        1Composite 模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致的处理对象和对象容器,无需关心处理的是单个对象,还是组合的对象容器。

2 、将“客户代码与复杂的对象容器结构”解耦是 Composite 模式的核心思想,解耦之后,客户代码将与纯粹的对象接口——而非对象容器的复杂内部实现结构——发生依赖关系,从而更能“应对变化”。

3Composite 模式中,是将“ AddRemove 的和对象容器相关的方法”定义在“表示抽象对象的 Component 类”中,还是将其定义在“表示对象容器的 Composite 类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡结构,这又是必须付出的代价。

4Composite 模式在具体实现中,可以让父对象中的字对象反向追溯:如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值