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. 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
  • 相关阅读:
    HDU 1069 Monkey and Banana
    HDU 1029 Ignatius and the Princess IV
    HDU 1024 Max Sum Plus Plus
    Gym100923H Por Costel and the Match
    Codeforces 682C Alyona and the Tree
    Codeforces 449B Jzzhu and Cities
    Codeforces (ccpc-wannafly camp day2) L. Por Costel and the Semipalindromes
    Codeforces 598D (ccpc-wannafly camp day1) Igor In the Museum
    Codeforces 1167c(ccpc wannafly camp day1) News Distribution 并查集模板
    快乐数问题
  • 原文地址:https://www.cnblogs.com/zyj649261718/p/6322480.html
Copyright © 2011-2022 走看看