zoukankan      html  css  js  c++  java
  • 设计模式学习笔记十七:组合模式(Composite Pattern)

         1.概述

         组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

         组合模式(Composite Pattern):将对象组合成树形结构以表示‘部分-整体’的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。

         组合模式结构图如下:

         结构图说明:

         (1)Component:组合中的对象声明接口,在适当情况下实现所有类共有的默认行为,声明一个接口用于访问和管理Component的子组件。在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。(可选)

         (2)Leaf:在组合中表示叶节点,叶节点没有子节点,定义对象的基本行为。

         (3)Composite:定义有子部件的那些部件的行为,存储子部件并在Component接口实现与子部件有关的操作。

         (4)Client:通过Component接口操作组合部件的对象。

         组合模式基本代码:

        public abstract class Component
        {
            
    protected string name;

            
    public Component(string name)
            {
                
    this.name = name;
            }

            
    public abstract void Add(Component c);
            
    public abstract void Remove(Component c);
            
    public abstract void Display(int depth);
        }

         Composite:

       public class Composite : Component
        {
            
    private List<Component> children = new List<Component>();

            
    public Composite(string name)
                : 
    base(name)
            { }

            
    public override void Add(Component c)
            {
                children.Add(c);
            }

            
    public override void Remove(Component c)
            {
                children.Remove(c);
            }

            
    public override void Display(int depth)
            {
                Console.WriteLine(
    new String('-', depth) + name);

                
    foreach (Component component in children)
                {
                    component.Display(depth 
    + 2);
                }
            }
        }

         Leaf:

        public class Leaf : Component
        {
            
    public Leaf(string name)
                : 
    base(name)
            { }

            
    public override void Add(Component c)
            {
                Console.WriteLine(
    "Cannot add to a leaf");
            }

            
    public override void Remove(Component c)
            {
                Console.WriteLine(
    "Cannot remove from a leaf");
            }

            
    public override void Display(int depth)
            {
                Console.WriteLine(
    new String('-', depth) + name);
            }
        }

         客户端:

        public class Program
        {
            
    static void Main(string[] args)
            {
                Composite root 
    = new Composite("root");
                root.Add(
    new Leaf("Leaf A"));
                root.Add(
    new Leaf("Leaf B"));

                Composite comp 
    = new Composite("Composite X");
                comp.Add(
    new Leaf("Leaf XA"));
                comp.Add(
    new Leaf("Leaf XB"));

                root.Add(comp);

                Composite comp2 
    = new Composite("Composite XY");
                comp2.Add(
    new Leaf("Leaf XYA"));
                comp2.Add(
    new Leaf("Leaf XYB"));

                comp.Add(comp2);

                root.Add(
    new Leaf("Leaf C"));

                Leaf leaf 
    = new Leaf("Leaf D");
                root.Add(leaf);
                root.Remove(leaf);

                root.Display(
    1);

                Console.Read();
            }
        }

         可以看出,Composite类型的对象可以包含其它Component类型的对象。换而言之,Composite类型对象可以含有其它的树枝(Composite)类型或树叶(Leaf)类型的对象。

         组合模式的实现根据所实现接口的区别分为两种形式,分别称为安全模式和透明模式。组合模式可以不提供父对象的管理方法,但组合模式必须在合适的地方提供子对象的管理方法(诸如:add、remove等)。安全式的组合模式要求管理聚集的方法只出现在树枝构件类中,而不出现在树叶构件中。与安全式的组合模式不同的是,透明式的组合模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定的接口。

         透明模式:也就是说在Component中声明所有用来管理子对象的方法,其中包括Add、Remove等。这样实现Component接口的所有子类都具备了Add和Remove。这样做的好处就是叶节点和枝节点对于外界没有区别,它们具有完全一致的行为接口,但问题也很明显,因为Leaf类本身不具备Add(),Remove()方法的功能,所以实现他是没有意义的。

         安全模式:就是在Component接口中不去声明Add和Remove方法,那么子类的Leaf也就不需要去实现它,而是在Composite声明所有用来管理子类对象的方法,这样就不会出现透明模式出现的问题,不过由于不够透明,所以叶节点和枝节点将不具有相同的接口,客户端调用需要做相应的判断,带来了不便。

         2.实例(大话设计模式)

         大话设计模式中的公司管理系统的结构图如下:

         具体实现代码如下:

    CompanyComposite

         客户端代码:

    Code

         在.NET中,一个典型的组合模式实例就是.NET的控件,如Button,TextBox和Label等,这些控件都是继承自Control类,该类自身包含ControlCollection的集合Controls,控件和子控件的逻辑关系如下图:

         3.总结

         何时采用组合模式:

         1.需求重要体现部分与整体的层次结构时

         2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象

         使用效果:

         1.Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化“一对一”的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。
         2.将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的复内部实现结构——发生依赖关系,从而更能“应对变化”。
         3.Composite模式中,是将“Add和Remove等和对象容器相关的方法”定义在“表示抽象对象的Component类”中,还是将其定义在“表示对象容器的Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡。这里有可能违背面向对象的“单一职责原则”,但是对于这种特殊结构,这又是必须付出的代价。ASP.NET控件的实现在这方面为我们提供了一个很好的示范。
         4.Composite模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。

         参考资料:

          大化设计模式

         http://terrylee.cnblogs.com/archive/2006/03/11/347919.html

  • 相关阅读:
    leetcode5 Longest Palindromic Substring
    leetcode17 Letter Combinations of a Phone Number
    leetcode13 Roman to Integer
    leetcode14 Longest Common Prefix
    leetcode20 Valid Parentheses
    leetcode392 Is Subsequence
    leetcode121 Best Time to Buy and Sell Stock
    leetcode198 House Robber
    leetcode746 Min Cost Climbing Stairs
    tomcat下使用druid配置jnid数据源
  • 原文地址:https://www.cnblogs.com/peida/p/1284686.html
Copyright © 2011-2022 走看看