24组合模式(Composite Pattern)

动机(Motivate):
    组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
意图(Intent):
    将对象组合成树形结构以表示“部分-整体”的层次结构。Composite模式使得用户对单个对象和组合对象的使用具有一致性。
                                                                                                                                    -----------《设计模式》GOF
结构图(Struct):
                            
生活中的例子:
                                            
适用性:   

    1.你想表示对象的部分-整体层次结构

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

图中橙色的区域表示的是复合图像元素。
示意性代码:

 1 public abstract class Graphics
 2 {
 3     protected string _name;
 4 
 5     public Graphics(string name)
 6     {
 7         this._name = name;
 8     }
 9     public abstract void Draw();
10 }
11 
12 public class Picture : Graphics
13 {
14     public Picture(string name)
15         : base(name)
16     { }
17     public override void Draw()
18     {
19         //
20     }
21 
22     public ArrayList GetChilds()
23     { 
24         //返回所有的子对象
25     }
26 }

而其他作为树枝构件,实现代码如下:

 1 public class Line:Graphics
 2 {
 3     public Line(string name)
 4         : base(name)
 5     { }
 6 
 7     public override void Draw()
 8     {
 9         Console.WriteLine("Draw a" + _name.ToString());
10     }
11 }
12 
13 public class Circle : Graphics
14 {
15     public Circle(string name)
16         : base(name)
17     { }
18 
19     public override void Draw()
20     {
21         Console.WriteLine("Draw a" + _name.ToString());
22     }
23 }
24 
25 public class Rectangle : Graphics
26 {
27     public Rectangle(string name)
28         : base(name)
29     { }
30 
31     public override void Draw()
32     {
33         Console.WriteLine("Draw a" + _name.ToString());
34     }
35 }

    现在我们要 对该图像元素进行处理:在客户端程序中,需要判断返回对象的具体类型到底是基本图像元素,还是复合图像元素。如果是复合图像元素,我们将要用递归去处理, 然而这种处理的结果却增加了客户端程序与复杂图像元素内部结构之间的依赖,那么我们如何去解耦这种关系呢?我们希望的是客户程序可以像处理基本图像元素一 样来处理复合图像元素,这就要引入Composite模式了,需要把对于子对象的管理工作交给复合图像元素,为了进行子对象的管理,它必须提供必要的Add()Remove()等方法,类结构图如下:


示意代码:

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

    这样引入Composite模式后,客户端程序不再依赖于复合图像元素的内部实现了。然而,我们程序中仍然存在着问题,因为LineRectangleCircle已经没有了子对象,它是一个基本图像元素,因此Add()Remove()的方法对于它来说没有任何意义,而且把这种错误不会在编译的时候报错,把错误放在了运行期,我们希望能够捕获到这类错误,并加以处理,稍微改进一下我们的程序:
 

 1 public class Line : Graphics
 2 {
 3     public Line(string name)
 4         : base(name)
 5     { }
 6 
 7     public override void Draw()
 8     {
 9         Console.WriteLine("Draw a" + _name.ToString());
10     }
11     public override void Add(Graphics g)
12     { 
13         //抛出一个我们自定义的异常
14     }
15     public override void Remove(Graphics g)
16     {
17         //抛出一个我们自定义的异常
18     }
19 }

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

示意代码:

 1 public abstract class Graphics
 2 {
 3     protected string _name;
 4 
 5     public Graphics(string name)
 6     {
 7         this._name = name;
 8     }
 9     public abstract void Draw();
10 }
11 
12 public class Picture : Graphics
13 {
14     protected ArrayList picList = new ArrayList();
15 
16     public Picture(string name)
17         : base(name)
18     { }
19     public override void Draw()
20     {
21         Console.WriteLine("Draw a" + _name.ToString());
22 
23         foreach (Graphics g in picList)
24         {
25             g.Draw();
26         }
27     }
28 
29     public void Add(Graphics g)
30     {
31         picList.Add(g);
32     }
33     public void Remove(Graphics g)
34     {
35         picList.Remove(g);
36     }
37 }
38 
39 public class Line : Graphics
40 {
41     public Line(string name)
42         : base(name)
43     { }
44 
45     public override void Draw()
46     {
47         Console.WriteLine("Draw a" + _name.ToString());
48     }
49 }
50 
51 public class Circle : Graphics
52 {
53     public Circle(string name)
54         : base(name)
55     { }
56 
57     public override void Draw()
58     {
59         Console.WriteLine("Draw a" + _name.ToString());
60     }
61 }
62 
63 public class Rectangle : Graphics
64 {
65     public Rectangle(string name)
66         : base(name)
67     { }
68 
69     public override void Draw()
70     {
71         Console.WriteLine("Draw a" + _name.ToString());
72     }
73 }

    这种方式属于安全式的Composite模式,在这种方式下,虽然避免了前面所讨论的错误,但是它也使得叶子节点和树枝构件具有不一样的接口。这种方式和透明式的Composite各有优劣,具体使用哪一个,需要根据问题的实际情况而定。通过Composite模式,客户程序在调用Draw()的时候不用再去判断复杂图像元素中的子对象到底是基本图像元素,还是复杂图像元素,看一下简单的客户端调用:

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


Composite模式实现要点:       

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438653.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

23装饰模式(Decorator Pattern)

子类复子类,子类何其多 假如我们需要为游戏中开发一种坦克,除了各种不同型号的坦克外,我们还希望在不同场合中为其增加以下一种或多种功能;比如红外线夜视功能,比如水陆两栖功能,比如卫星定位功能等等。 按类继承的作法…

gb2312编码在线转换_python基础学习—04字符串与编码

点击上方蓝字关注我们不迷路!字符串与编码一、了解计算机编码1.1 编码定义:将信息从一种形式转换为另外一种形式的过程叫做编码,即信息转换过程举例:信息加密解密、语言翻译1.2 计算机编码定义:将计算机可读信息转换…

25外观模式(Facade Pattern)

动机(Motivate): 在软件开发系统中,客户程序经常会与复杂系统的内部子系统之间产生耦合,而导致客户程序随着子系统的变化而变化。那么如何简化客户程序与子系统之间的交互接口?如何将复杂系统的内部子系统与客户程序之间的依赖解耦&#…

mysql mybatis类型对应_Mybatis与数据库的类型对应

Mybatis与数据库的类型对应由于业务的改变,在首次存入数据库时某些int属性并没有赋值,于是默认值就开始污染数据库了。java实体属性对应mysql和SQL Server 和Oracle 数据类型对应1:Java数据类型与MySql数据类型对照表*对于bolb,一…

26享元模式(Flyweight Pattern)

面向对象的代价 面向对象很好地解决了系统抽象性的问题,同时在大多数情况下,也不会损及系统的性能。但是,在 某些特殊的应用中下,由于对象的数量太大,采用面向对象会给系统带来难以承受的内存开销。比如: 图形应用…

mysql一个事务多个log_MySQL识别一个binlog中的一个事物

MySQL测试版本5.7.14设置GTID_MODEONON(3): Both new and replicated transactions must be GTID transactions(生成的是GTID事物,slave也只能应用GTID事物)设置binlog格式为row模式做如下操作mysql> insert into test values(1,2);Query OK, 1 row affected (0.…

go for 循环遍历数组并排序_10. Go语言流程控制:for 循环

本文原文:http://golang.iswbm.comGithub:http://github.com/iswbm/GolangCodingTimeGo里的流程控制方法还是挺丰富,整理了下有如下这么多种:if - else 条件语句switch - case 选择语句for - range 循环语句goto 无条件跳转语句de…

27代理模式(Proxy Pattern)

直接与间接: 人们对复杂的软件系统常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活、 满足特定需求的解决方案。 …

31模板方法(Template Method)

无处不在的Template Method 如果你只想掌握一种设计模式,那么它就是Template Method! 动机(Motivate): 变化 -----是软件设计的永恒主题,如何管理变化带来的复杂性?设计模式的艺术性和复杂度就在于如何 分析,并发现系统中…

bat 脚本清空窗口内容_tomcat9.0启动脚本startup.bat的分析

1、 Apache Tomcat的下载和安装从Apache官网https://tomcat.apache.org/可以下载各种版本的tomcat软件,下载的文件格式可以是zip/tar.gz/exe形式的。如下图所示,在64位windows中使用tomcat,我们可以下载"64-bit Windows.zip",直接解…

33迭代器模式(Iterator Pattern)

动机(Motivate): 在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“ 同一种算法在多种集合对象上进行操作…

32命令模式(Command Pattern)

耦合与变化: 耦合是软件不能抵御变化灾难的根本性原因。不仅实体对象与实体对象之间存在耦合关系,实体对象与行为操作之间也存在耦合关系。 动机(Mot…

34观察者模式(Observer Pattern)

动机(Motivate):在软件构建 过程中,我们需要为某些对象建立一种“通知依赖关系” --------一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密&#x…

36中介者模式(Mediator Pattern)

依赖关系的转化: 动机(Motivate): 在软件构建过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断的变化。 在这种情况…

相似理论与模型试验_正交实验下的固液耦合相似材料研究

原标题:基于正交试验的固液耦合相似材料研究摘 要:为了研究矿井突水演化规律,通过正交试验研制出一种能同时满足固体力学与水理性的固液 耦合相似材料,该相似材料以河沙为骨料、水泥和大白粉为胶结剂、液体石蜡和淀粉为调节剂。采用 极差分析…

35解释器模式(Interpreter Pattern)

动机(Motivate): 在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化。 在这种情况下,将特定领域的问题表达为某种文法规则下的句子,…

37职责链模式(Chain of Responsibility Pattern)

动机(Motivate): 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者的紧耦合。 如何使请求的发送者不需要指定具体的接受…

python3中format函数列表_Python3之字符串格式化format函数详解(上)

173.jpg概述在Python3中,字符串格式化操作通过format()方法或者fstring实现。而相比于老版的字符串格式化方式,format()方法拥有更多的功能,操作起来更加方便,可读性也更强。该函数将字符串当成一个模板,通过传入的参数…

38备忘录模式(Memento Pattern)

对象状态的回溯: 对象状态的变化无端,如何回溯/恢复对象在某个点的状态? 动机: 在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够…

39策略模式(Strategy Pattern)

算法与对象的耦合: 对象可能经常需要使用多种不同的算法,但是如果变化频繁,会将类型变得脆弱... 动机: 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将…