博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式:组合模式(Composite Pattern)
阅读量:5840 次
发布时间:2019-06-18

本文共 4856 字,大约阅读时间需要 16 分钟。

作者:  创建于:2006-03-11 出处:  收录于:2013-02-28

结构图


 

意图


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

适用性


  • 你想表示对象的部分-整体层次结构。
  • 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。 

实现代码


 这里我们用绘图这个例子来说明Composite模式,通过一些基本图像元素(直线、圆等)以及一些复合图像元素(由基本图像元素组合而成)构建复杂的图形树。在设计中我们对每一个对象都配备一个Draw()方法,在调用时,会显示相关的图形。可以看到,这里复合图像元素它在充当对象的同时,又是那些基本图像元素的一个容器。先看一下基本的类结构图:

1 using System; 2 using System.Collections; 3 public abstract class Graphics 4 { 5     protected string _name; 6     public Graphics(string name) 7     { 8         this._name = name; 9     }10     public abstract void Draw();11     public abstract void Add();12     public abstract void Remove();13 }14 public class Picture : Graphics15 {16     protected ArrayList picList = new ArrayList();17     public Picture(string name) : base(name)18     { }19     public override void Draw()20     {21         Console.WriteLine("Draw a" + _name.ToString());22         foreach (Graphics g in picList)23         {24             g.Draw();25         }26     }27     public override void Add(Graphics g)28     {29         picList.Add(g);30     }31     public override void Remove(Graphics g)32     {33         picList.Remove(g);34     }35 }36 public class Line : Graphics37 {38     public Line(string name) : base(name)39     { }40     public override void Draw()41     {42         Console.WriteLine("Draw a" + _name.ToString());43     }44     public override void Add(Graphics g)45     {46         //抛出一个我们自定义的异常47     }48     public override void Remove(Graphics g)49     {50         //抛出一个我们自定义的异常51     }52 }53 public class Circle : Graphics54 {55     public Circle(string name): base(name)56     { }57     public override void Draw()58     {59         Console.WriteLine("Draw a" + _name.ToString());60     }61     public override void Add(Graphics g)62     {63         //抛出一个我们自定义的异常64     }65     public override void Remove(Graphics g)66     {67         //抛出一个我们自定义的异常68     }69 }70 public class Rectangle : Graphics71 {72     public Rectangle(string name): base(name)73     { }74     public override void Draw()75     {76         Console.WriteLine("Draw a" + _name.ToString());77     }78     public override void Add(Graphics g)79     {80         //抛出一个我们自定义的异常81     }82     public override void Remove(Graphics g)83     {84         //抛出一个我们自定义的异常85     }86 }

因为Line,Rectangle,Circle已经没有了子对象,它是一个基本图像元素,因此Add(),Remove()的方法对于它来说没有任何意义,而且把这种错误不会在编译的时候报错,所以需要抛出异常。

这样改进以后,我们可以捕获可能出现的错误,做进一步的处理。上面的这种实现方法属于透明式的Composite模式,如果我们想要更安全的一种做法,就需要把管理子对象的方法声明在树枝构件Picture类里面,这样如果叶子节点Line,Rectangle,Circle使用这些方法时,在编译期就会出错,看一下类结构图:

1 using System; 2 using System.Collections; 3 public abstract class Graphics 4 { 5     protected string _name; 6     public Graphics(string name) 7     { 8         this._name = name; 9     }10     public abstract void Draw();11 }12 public class Picture : Graphics13 {14     protected ArrayList picList = new ArrayList();15     public Picture(string name): base(name)16     { }17     public override void Draw()18     {19         Console.WriteLine("Draw a" + _name.ToString());20         foreach (Graphics g in picList)21         {22             g.Draw();23         }24     }25     public void Add(Graphics g)26     {27         picList.Add(g);28     }29     public void Remove(Graphics g)30     {31         picList.Remove(g);32     }33 }34 public class Line : Graphics35 {36     public Line(string name): base(name)37     { }38     public override void Draw()39     {40         Console.WriteLine("Draw a" + _name.ToString());41     }42 }43 public class Circle : Graphics44 {45     public Circle(string name) : base(name)46     { }47     public override void Draw()48     {49         Console.WriteLine("Draw a" + _name.ToString());50     }51 }52 public class Rectangle : Graphics53 {54     public Rectangle(string name) : base(name)55     { }56     public override void Draw()57     {58         Console.WriteLine("Draw a" + _name.ToString());59     }60 }

这种方式属于安全式的Composite模式,在这种方式下,虽然避免了前面所讨论的错误,但是它也使得叶子节点和树枝构件具有不一样的接口。这种方式和透明式的Composite各有优劣,具体使用哪一个,需要根据问题的实际情况而定。

以下是客户端代码

1 public class App 2 { 3     public static void Main() 4     { 5         Picture root = new Picture("Root"); 6         root.Add(new Line("Line")); 7         root.Add(new Circle("Circle")); 8         Rectangle r = new Rectangle("Rectangle"); 9         root.Add(r);10         root.Draw();11     }12 }

效果及实现要点


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

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

3.Composite模式中,是将“Add和Remove等和对象容器相关的方法”定义在“表示抽象对象的Component类”中,还是将其定义在“表示对象容器的Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡。这里有可能违背面向对象的“单一职责原则”,但是对于这种特殊结构,这又是必须付出的代价。ASP.NET控件的实现在这方面为我们提供了一个很好的示范。

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

 

转载于:https://www.cnblogs.com/Ming8006/archive/2013/02/28/2937344.html

你可能感兴趣的文章
CITRIX XenAPP/TS打印管理ThinPrint.
查看>>
杨辉三角绘图C语言
查看>>
SQL Server以Online模式创建索引
查看>>
微软开放 .NET 框架源代码
查看>>
Win2008 R2 VDI动手实验系列之五:配置远程桌面Web访问
查看>>
Jira迁移及内存调整
查看>>
综合应用WPF/WCF/WF/LINQ之十六:关于更改XBAP程序的配置文件的问题
查看>>
CCNA系列课程(5)IP路由基础
查看>>
Exchange Server 2010 SP2 新功能简述
查看>>
使用wxWidgets for C++从资源文件中静态装载图像
查看>>
提高数据库安全性的办法
查看>>
工作流编程循序渐进(8:状态机工作流)
查看>>
3.VMware View 4.6安装与部署-connection server(View Standard Server)
查看>>
Lync Server 2013 实战系列之六:标准版-安装和更新LyncServer 系统
查看>>
C#事件(event)解析
查看>>
MariaDB日志审计 帮你揪出内个干坏事儿的小子
查看>>
Reporting Services目录临时数据库文件存在
查看>>
一个Windows Mobile, Windows Embedded CE工程师的找工经历(一)
查看>>
终于有了MSDN上的Blog
查看>>
linux内核input子系统解析【转】
查看>>