zoukankan      html  css  js  c++  java
  • C#设计模式(10)——组合模式

    一、概念

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

    二、组合模式类图

    1、透明式的组合模式类图:

    2、安全式组合模式的类图:

    三、代码实现

    1、透明式的组合模式

    // 通过一些简单图形以及一些复杂图形构建图形树来演示组合模式
        // 客户端调用
        class Client
        {
            static void Main(string[] args)
            {
                ComplexGraphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");
                complexGraphics.Add(new Line("线段A"));
                ComplexGraphics CompositeCG = new ComplexGraphics("一个圆和一条线组成的复杂图形");
                CompositeCG.Add(new Circle(""));
                CompositeCG.Add(new Circle("线段B"));
                complexGraphics.Add(CompositeCG);
                Line l = new Line("线段C");
                complexGraphics.Add(l);
    
                // 显示复杂图形的画法
                Console.WriteLine("复杂图形的绘制如下:");
                Console.WriteLine("---------------------");
                complexGraphics.Draw();
                Console.WriteLine("复杂图形绘制完成");
                Console.WriteLine("---------------------");
                Console.WriteLine();
    
                // 移除一个组件再显示复杂图形的画法
                complexGraphics.Remove(l);
                Console.WriteLine("移除线段C后,复杂图形的绘制如下:");
                Console.WriteLine("---------------------");
                complexGraphics.Draw();
                Console.WriteLine("复杂图形绘制完成");
                Console.WriteLine("---------------------");
                Console.Read();
            }
        }
    
        /// <summary>
        /// 图形抽象类,
        /// </summary>
        public abstract class Graphics
        {
            public string Name { get; set; }
            public Graphics(string name)
            {
                this.Name = name;
            }
    
            public abstract void Draw();
            public abstract void Add(Graphics g);
            public abstract void Remove(Graphics g);
        }
    
        /// <summary>
        /// 简单图形类——线
        /// </summary>
        public class Line : Graphics
        {
            public Line(string name)
                : base(name)
            { }
    
            // 重写父类抽象方法
            public override void Draw()
            {
                Console.WriteLine("" + Name);
            }
            // 因为简单图形在添加或移除其他图形,所以简单图形Add或Remove方法没有任何意义
            // 如果客户端调用了简单图形的Add或Remove方法将会在运行时抛出异常
            // 我们可以在客户端捕获该类移除并处理
            public override void Add(Graphics g)
            {
                throw new Exception("不能向简单图形Line添加其他图形");
            }
            public override void Remove(Graphics g)
            {
                throw new Exception("不能向简单图形Line移除其他图形");
            }
        }
    
        /// <summary>
        /// 简单图形类——圆
        /// </summary>
        public class Circle : Graphics
        {
            public Circle(string name)
                : base(name)
            { }
    
            // 重写父类抽象方法
            public override void Draw()
            {
                Console.WriteLine("" + Name);
            }
    
            public override void Add(Graphics g)
            {
                throw new Exception("不能向简单图形Circle添加其他图形");
            }
            public override void Remove(Graphics g)
            {
                throw new Exception("不能向简单图形Circle移除其他图形");
            }
        }
    
        /// <summary>
        /// 复杂图形,由一些简单图形组成,这里假设该复杂图形由一个圆两条线组成的复杂图形
        /// </summary>
        public class ComplexGraphics : Graphics
        {
            private List<Graphics> complexGraphicsList = new List<Graphics>();
    
            public ComplexGraphics(string name)
                : base(name)
            { }
    
            /// <summary>
            /// 复杂图形的画法
            /// </summary>
            public override void Draw()
            {          
                foreach (Graphics g in complexGraphicsList)
                {
                    g.Draw();
                }
            }
    
            public override void Add(Graphics g)
            {
                complexGraphicsList.Add(g);
            }
            public override void Remove(Graphics g)
            {
                complexGraphicsList.Remove(g);
            }
        }

    2、安全式组合模式

    /// 安全式的组合模式
        /// 此方式实现的组合模式把管理子对象的方法声明在树枝构件ComplexGraphics类中
        /// 这样如果叶子节点Line、Circle使用了Add或Remove方法时,就能在编译期间出现错误
        /// 但这种方式虽然解决了透明式组合模式的问题,但是它使得叶子节点和树枝构件具有不一样的接口。
        /// 所以这两种方式实现的组合模式各有优缺点,具体使用哪个,可以根据问题的实际情况而定
        class Client
        {
            static void Main(string[] args)
            {
                ComplexGraphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");
                complexGraphics.Add(new Line("线段A"));
                ComplexGraphics CompositeCG = new ComplexGraphics("一个圆和一条线组成的复杂图形");
                CompositeCG.Add(new Circle(""));
                CompositeCG.Add(new Circle("线段B"));
                complexGraphics.Add(CompositeCG);
                Line l = new Line("线段C");
                complexGraphics.Add(l);
    
                // 显示复杂图形的画法
                Console.WriteLine("复杂图形的绘制如下:");
                Console.WriteLine("---------------------");
                complexGraphics.Draw();
                Console.WriteLine("复杂图形绘制完成");
                Console.WriteLine("---------------------");
                Console.WriteLine();
    
                // 移除一个组件再显示复杂图形的画法
                complexGraphics.Remove(l);
                Console.WriteLine("移除线段C后,复杂图形的绘制如下:");
                Console.WriteLine("---------------------");
                complexGraphics.Draw();
                Console.WriteLine("复杂图形绘制完成");
                Console.WriteLine("---------------------");
                Console.Read();
            }
        }
    
        /// <summary>
        /// 图形抽象类,
        /// </summary>
        public abstract class Graphics
        {
            public string Name { get; set; }
            public Graphics(string name)
            {
                this.Name = name;
            }
    
            public abstract void Draw();
            // 移除了Add和Remove方法
            // 把管理子对象的方法放到了ComplexGraphics类中进行管理
            // 因为这些方法只在复杂图形中才有意义
        }
    
        /// <summary>
        /// 简单图形类——线
        /// </summary>
        public class Line : Graphics
        {
            public Line(string name)
                : base(name)
            { }
    
            // 重写父类抽象方法
            public override void Draw()
            {
                Console.WriteLine("" + Name);
            }
        }
    
        /// <summary>
        /// 简单图形类——圆
        /// </summary>
        public class Circle : Graphics
        {
            public Circle(string name)
                : base(name)
            { }
    
            // 重写父类抽象方法
            public override void Draw()
            {
                Console.WriteLine("" + Name);
            }
        }
    
        /// <summary>
        /// 复杂图形,由一些简单图形组成,这里假设该复杂图形由一个圆两条线组成的复杂图形
        /// </summary>
        public class ComplexGraphics : Graphics
        {
            private List<Graphics> complexGraphicsList = new List<Graphics>();
            public ComplexGraphics(string name)
                : base(name)
            { }
    
            /// <summary>
            /// 复杂图形的画法
            /// </summary>
            public override void Draw()
            {
                foreach (Graphics g in complexGraphicsList)
                {
                    g.Draw();
                }
            }
    
            public void Add(Graphics g)
            {
                complexGraphicsList.Add(g);
            }
            public void Remove(Graphics g)
            {
                complexGraphicsList.Remove(g);
            }
        }

    四、组合模式中三个角色

    • 抽象构件(Component)角色:这是一个抽象角色,上面实现中Graphics充当这个角色,它给参加组合的对象定义出了公共的接口及默认行为,可以用来管理所有的子对象(在透明式的组合模式是这样的)。在安全式的组合模式里,构件角色并不定义出管理子对象的方法,这一定义由树枝结构对象给出。
    • 树叶构件(Leaf)角色:树叶对象时没有下级子对象的对象,上面实现中Line和Circle充当这个角色,定义出参加组合的原始对象的行为
    • 树枝构件(Composite)角色:代表参加组合的有下级子对象的对象,上面实现中ComplexGraphics充当这个角色,树枝对象给出所有管理子对象的方法实现,如Add、Remove等。

    五、组合模式优缺点

      优点:

    1. 组合模式使得客户端代码可以一致地处理对象和对象容器,无需关系处理的单个对象,还是组合的对象容器。
    2. 将”客户代码与复杂的对象容器结构“解耦。
    3. 可以更容易地往组合对象中加入新的构件。

      缺点:使得设计更加复杂。客户端需要花更多时间理清类之间的层次关系。(这个是几乎所有设计模式所面临的问题)。

      注意的问题:

    1. 有时候系统需要遍历一个树枝结构的子构件很多次,这时候可以考虑把遍历子构件的结构存储在父构件里面作为缓存。
    2. 客户端尽量不要直接调用树叶类中的方法(在我上面实现就是这样的,创建的是一个树枝的具体对象,应该使用Graphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");),而是借用其父类(Graphics)的多态性完成调用,这样可以增加代码的复用性。

    六、组合模式的使用场景

    1. 需要表示一个对象整体或部分的层次结构。
    2. 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
  • 相关阅读:
    LINQ to XML 操作XML文档
    C#2008与.NET 3.5 高级程序设计读书笔记(3)C#核心编程结构I
    阐述集合类的接口(IEnumerable,IEnumerator,ICollection,IList,IDictionary)
    山塞一个PetShop(Task001)——基本的数据库连接
    山寨一个PetShop(Task002)——数据类库Model
    自定义控件(Task01)——可以设置属性的控件
    ASP.NET连接SQL、Access、Excel数据库(三)——工厂模式
    ASP.NET连接SQL、Access、Excel数据库(一)——什么是ADO.NET
    ASP.NET 2.0 的数据绑定控件概述与区别(GridView、DetailsView、FormView 、Repeater、DataList)
    ASP.NET连接SQL、Access、Excel数据库(二)——连接实例
  • 原文地址:https://www.cnblogs.com/zyj649261718/p/6322480.html
Copyright © 2011-2022 走看看