C#设计模式(八)组合模式

来源:互联网 发布:适合打lol的鼠标 知乎 编辑:程序博客网 时间:2024/06/08 06:15

一、引言

在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象和复合对象在功能上区别,导致在操作过程中必须区分简单对象和复合对象,这样就会导致客户调用带来不必要的麻烦,然而作为客户,它们希望能够始终一致地对待简单对象和复合对象。然而组合模式就是解决这样的问题。下面让我们看看组合模式是怎样解决这个问题的。

二、组合模式的详细介绍

2.1 组合模式的定义

组合模式允许你将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以一致的方式处理单个对象以及对象的组合。下面我们用绘制的例子来详细介绍组合模式,图形可以由一些基本图形元素组成(如直线,圆等),也可以由一些复杂图形组成(由基本图形元素组合而成),为了使客户对基本图形和复杂图形的调用保持一致,我们使用组合模式来达到整个目的。

组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进行一致处理的原因。

2.2 组合模式的实现

介绍完组合模式的定义之后,让我们以图形的例子来实现组合模式,具体代码如下:

class Program    {        static void Main(string[] args)        {            ComplexGraphic complexGraphics = new ComplexGraphic("一个复杂图形和一个线段");            ComplexGraphic CompositeCG = new ComplexGraphic("两个线段");            CompositeCG.Add(new line("第一个线段"));            CompositeCG.Add(new line("第二个线段"));            complexGraphics.Add(CompositeCG);            line l = new line("线段C");            complexGraphics.Add(l);            complexGraphics.Draw();//得到结果:画第一个线段                                   //画第二个线段            l.Add(new line("l2"));//dram的时候throw一个execption            Console.ReadLine();        }        /// <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);            }            public override void Remove(Graphics g)            {                throw new Exception("简单图形line不能删除其他图形");            }            public override void Add(Graphics g)            {                throw new Exception("简单图形line不能添加其他图形");            }        }        /// <summary>        /// 复杂图形,由一些简单图形组成        /// </summary>        public class ComplexGraphic : Graphics        {            private List<Graphics> complexGraphicsList = new List<Graphics>();            public ComplexGraphic(string name) : base(name) { }            public override void Add(Graphics g)            {                complexGraphicsList.Add(g);            }            public override void Remove(Graphics g)            {                complexGraphicsList.Remove(g);            }            public override void Draw()            {                foreach (Graphics g in complexGraphicsList)                {                    g.Draw();                }            }        }    }
由于基本图形对象不存在Add和Remove方法,上面实现中直接通过抛出一个异常的方式来解决这样的问题的,但是我们想以一种更安全的方式来解决——因为基本图形根本不存在这样的方法,我们是不是可以移除这些方法呢?为了移除这些方法,我们就不得不修改Graphics接口,我们把管理子对象的方法声明放在复合图形对象里面,这样简单对象Line、Circle使用这些方法时在编译时就会出错,这样的一种实现方式我们称为安全式的组合模式,然而上面的实现方式称为透明式的组合模式,下面让我们看看安全式的组合模式又是怎样实现的,具体实现代码如下:

class Program    {/// 安全式的组合模式        /// 此方式实现的组合模式把管理子对象的方法声明在树枝构件ComplexGraphics类中        /// 这样如果叶子节点Line、Circle使用了Add或Remove方法时,就能在编译期间出现错误        /// 但这种方式虽然解决了透明式组合模式的问题,但是它使得叶子节点和树枝构件具有不一样的接口。        /// 所以这两种方式实现的组合模式各有优缺点,具体使用哪个,可以根据问题的实际情况而定        static void Main(string[] args)        {            ComplexGraphics complexGraphics = new ComplexGraphics("一个复杂图形和一个线段");            ComplexGraphics CompositeCG = new ComplexGraphics("两个线段");            CompositeCG.Add(new Line("第一个线段"));            CompositeCG.Add(new Line("第二个线段"));            complexGraphics.Add(CompositeCG);            Line l = new Line("线段C");            complexGraphics.Add(l);            complexGraphics.Draw();//得到结果:画第一个线段                        Console.ReadLine();        }        /// <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);            }        }

三、组合模式的优缺点

优点:

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

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




0 0
原创粉丝点击