树形结构是软件行业很常见的一种结构,几乎随处可见,  比如: HTML 页面中的DOM,产品的分类,通常一些应用或网站的菜单,Windows Form 中的控件继承关系,Android中的View继承关系,部门的组织架构,Windows 资源管理器 等等都是树形结构。

Windows 资源管理

树形结构是很有特点的一种数据结构,  下图是一棵树:

树结构有几个术语:

根节点:最高的节点被称为根节点,上图中的红色节点是根节点。根节点没有父节点。

父节点:如果一个节点的下面链接着其它节点那上层节点被称作该节点的父节点,下层节点被称作父节点的子节点。除了根节点外子节点有且只有一个父节点。上图中的红色和黄色都是父节点。

叶子节点:每一个节点有0个或多个子节点。有0个(没有)子节点的节点称作叶子节点。上图中的绿色节点都是叶子节点。

如果要给树形结构上增加或者删除一些节点该如何处理呢? 组合模式提供了面向对象优雅的处理这种数据结构的方法。

一、组合模式的定义

组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。

二、组合模式结构图

组合模式结构图

1、Component(抽象构件):

它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。

2 、Composite(容器构件):

它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

3、Leaf(叶子构件):

它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。

三、组合模式的示例代码

public abstract class Component
{public abstract void Operaton(int depth);public abstract void Add(Component component);public abstract void Remove(Component component);public abstract Component GetChild(int i);
}public class Composite : Component
{private IList<Component> components = new List<Component>();public override void Operaton(int depth){Console.WriteLine(new String(' ', depth - 2) + "|");Console.WriteLine(new String(' ', depth - 2) + "--" + this.GetType().Name + " Opration");foreach (var component in components){component.Operaton(depth + 2);}}public override void Add(Component component){components.Add(component);}public override void Remove(Component component){components.Remove(component);}public override Component GetChild(int i){return components[i];}
}
public class Leaf : Component
{public override void Operaton(int depth){Console.WriteLine(new String(' ', depth - 2) + "|");Console.WriteLine(new String(' ', depth - 2) + "--" + this.GetType().Name + " Opration");}public override void Add(Component component){Console.WriteLine("Cannot add to a leaf");}public override void Remove(Component component){Console.WriteLine("Cannot remove from a leaf");}public override Component GetChild(int i){throw new Exception("Cannot get a child from a leaf");}
}

客户端调用:

static void Main(string[] args)
{Component root = new Composite.Structure.Composite();root.Add(new Leaf());root.Add(new Leaf());var composite = new Composite.Structure.Composite();composite.Add(new Leaf());composite.Add(new Leaf());root.Add(composite);var componsite2 = new Composite.Structure.Composite();composite.Add(componsite2);componsite2.Add(new Leaf());componsite2.Add(new Leaf());root.Operaton(2);Console.ReadKey();
}

输出结果

四、组合模式实例

现在有一个新闻系统,这个新闻系统里有若干类别,每一个子类里又包含若干分类,理论上是一个无限级的树形结构,同时每个分类上都可能包含具体的新闻。结构如下:

新闻系统分类组织机构图

上图中的白色部分表示分类(Category),绿色部分表示新闻(News), 现在要添加新闻的分类,删除新闻,以及将新闻展示出来。下面我们用组合模式来实现这些功能.

通过分析,可以提出构件 NewsComponent, News 和Category 三个对象,NewsComponent相当于组合模式的抽象构建,Category相当于 容器构建,News相当于叶子构建。这样我们就可以画出新闻系统核心UML图:

新闻系统代码:

public abstract class NewsComponent
{protected string title;public NewsComponent(string title){this.title = title;}public abstract void Add(NewsComponent newsComponent);public abstract void Remove(NewsComponent newsComponent);public abstract void Display(int depath);
}public class Category : NewsComponent
{private IList<NewsComponent> categories = new List<NewsComponent>();public Category(string title):base(title){}public override void Add(NewsComponent newsComponent){categories.Add(newsComponent);}public override void Remove(NewsComponent newsComponent){categories.Add(newsComponent);}public override void Display(int depath){Console.WriteLine(new String('-', depath) + title);foreach (var category in categories){category.Display(depath+2);}}
}
public  class News: NewsComponent
{private string content;public News(string title, string content):base(title){this.content = content;}public override void Add(NewsComponent newsComponent){Console.WriteLine("Cannot add to a News");}public override void Remove(NewsComponent newsComponent){Console.WriteLine("Cannot remove from a News");}public override void Display(int depath){Console.WriteLine(new String('-', depath) + this.title + "[content]:" + this.content);}
}

客户端调用:

static void Main(string[] args)
{NewsComponent newsComponent = new Category("新闻");newsComponent.Add(new Category("政治新闻"));newsComponent.Add(new News("【政治头条】-美国大选 特朗普生出将于将在北京时间明日凌晨3:45宣誓就职美国总统", "..."));newsComponent.Add(new Category("政治风云"));var a = new Category("娱乐新闻");a.Add(new News("【娱乐头条】-由王安全执导的<<监狱风云>>将于今天0点在各大影院全面上映", "...."));a.Add(new Category("娱乐八卦"));newsComponent.Add(a);var b = new Category("财经新闻");b.Add(new News("【财经头条】-由于受土耳其货币危机的影响,美国及欧洲股市全线跌幅超1%", "..."));var c = new Category("股市风云");b.Add(c);c.Add(new Category("欧洲股市"));c.Add(new Category("美股风云"));c.Add(new Category("日韩股市"));newsComponent.Add(b);var d = new Category("体育新闻");var e = new Category("篮球");d.Add(e);var f=new Category("NBA");var g= new Category("CBA");e.Add(g);e.Add(f);newsComponent.Add(d);           newsComponent.Display(1);Console.ReadKey();
}

输出结果:

五、透明组合模式与安全组合模式

在上面的实例中我们发现,Component构件类中出现了Add,Remove方法,但是在叶子节点类(Leaf)中不得不去实现,但是叶子节点是不需要这些方法的,看起来有些鸡肋。虽然客户端实现了无差别调用,虽然可以针对抽象编程,但是一旦调用到了叶子节点的这些方法,软件可能会出现异常或者无意义的调用。那么我们有什么方法来改变呢?

可以将这些方法从Component中移到Composite 中,这样就可以避免这种情况。只在Component中定义Composite和Leaf公用的方法。

那么组合模式的结构图就变成这样:

这时图中的各个角色没有变化,仅仅是在Component去掉了一些抽象方法,在调用的时就不能用抽象构建Component来声明了,要用具体的Composite来声明,这样在客户端调用时就需要区别对待Composite和Leaf了,不能针对抽象Component构件编程了。

1、Component2(抽象构件):

它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。

2 、Composite2(容器构件):

它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

3、Leaf2(叶子构件):

它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。

在组合模式中根据抽象构建定义的形式, 可以将组合模式更称 安全组合模式和透明组合模式。

安全组合模式:

安全组合模式只在抽象构件类中定义叶子节点(Leaf)和容器节点(Composite)都共有的方法,将容器方法移至容器节点中, 它的一般结构如下图:

安全组合模式UML图

安全模式的好处是,在客户端调用叶子节点时不会出现调用不安全的方法,因为叶子节点没有该方法,抽象构件中也没有该方法。不好的地方是,叶子节点和容器节点的实现出现了差别,不能在客户端统一使用抽象构件(Component)来编程了,必须要区别对待叶子节点(Leaf)和容器节点(Component)。

透明组合模式

透明组合模式是将对容器构件的管理方法都定义在抽象构件(Component)中,在叶子节点(Leaf)和容器节点(Composite)都进行实现,在叶子节点中针对相关的管理方法进行相关异常处理,或者友好提示的处理实现,  一般情况下透明组合模式的UML如下:

透明模式UML图

透明模式的好处是可以给客户端调用时提供统一,无差别的对待叶子节点(Leaf)和容器节点(Composite),并且可以针对抽象构件(Component)进行编程。透明模式的缺点是如果调用到叶子节点(Leaf) 上的相关方法会导致程序异常。

六、组合模式的优点

  1. 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
  2. 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
  3. 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
  4. 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

七、组合模式的缺点

组合模式,控制容器节点的类型不太容易。

八、组合模式的使用场景

  1. 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们。
  2. 在一个使用面向对象语言开发的系统中需要处理一个树形结构。
  3. 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型。

Composite模式在平常的开发过程中使用的非常多,因为他提供了一种面向对象的操作树形结构的方法,树形结构在开发中频繁出现。

转载于:https://www.cnblogs.com/vaiyanzi/p/9503625.html

【设计模式】组合模式 Composite Pattern相关推荐

  1. C#设计模式——组合模式(Composite Pattern)

    一.概述 在软件开发中,我们往往会遇上类似树形结构的对象体系.即某一对象既可能在树形结构中作为叶节点存在,也可能作为分支节点存在.比如在文件系统中,文件是作为叶节点存在,而文件夹就是分支节点.在设计这 ...

  2. 设计模式:组合模式(Composite Pattern)

    组合模式: 又叫部分整体模式, 它创建了对象组的树形结构,将对象组合成树状结构以表示"整体-部分"的层次关系. JDK中的HashMap就使用了组合模式 public abstra ...

  3. Java设计模式 —— 组合模式(Composite)

    Java设计模式 -- 组合模式(Composite) 定义 Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性. ...

  4. python 设计模式之组合模式Composite Pattern

    #引入一 文件夹对我们来说很熟悉,文件夹里面可以包含文件夹,也可以包含文件. 那么文件夹是个容器,文件夹里面的文件夹也是个容器,文件夹里面的文件是对象. 这是一个树形结构 咱们生活工作中常用的一种结构 ...

  5. 24组合模式(Composite Pattern)

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

  6. 设计模式 -- 组合模式(Composite)

    写在前面的话:读书破万卷,编码如有神 -------------------------------------------------------------------- 主要内容包括: 初识组合 ...

  7. 组合模式(Composite Pattern)

    组合模式概述 定义:组合多个对象形成树形结构以表示具有部分-整体关系的层次结构.组合模式让客户端可以统一对待单个对象和组合对象.又被成为"部分-整体"(Part-Whole)模式, ...

  8. 组合模式测试组合模式(Composite Pattern)

    改章节是一篇关于组合模式测试的帖子 像一个树形结构一样使用基本的对象和自己本身构建一个复杂的对象,称为组合模式. 这类模式很轻易学习以及应用到某个系统中.组合模式属于结构设计模式之一,比拟常用.经典的 ...

  9. 组合模式-Composite Pattern

    目录 组合模式的定义与特点 组合模式的结构与实现 组合模式的应用实例 组合模式的应用场景 组合模式的扩展 树形结构在软件中随处可见,例如操作系统中的目录结构.应用软件中的菜单.办公系统中的公司组织结构 ...

最新文章

  1. 郭天祥:我的大学六年
  2. Java 基础知识 练习
  3. 不同浏览器前端调试查看返回页面的json数据
  4. nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
  5. linux 文件备份定时任务脚本,linux服务器每天执行备份数据库定时任务脚本demo
  6. ubuntu之Unable to lock the administration directory(/var/lib/dpkg/), are you root?13 Permission denie
  7. 光端机使用过程中碰到的九大问题
  8. LED显示驱动(七):图层基本测试总结
  9. python re span_Python的re模块与正则表达式小结
  10. 宽度学习(BLS)网络的研究和应用
  11. 【渗透测试】Sunlogin-RCE(向日葵)
  12. android 脚本发短信,Android使用Intent发送短信的实现方法
  13. html流控破解脚本,tc 流控脚本
  14. 毕业论文开题报告模板
  15. wps html编辑表格,手机wps中怎样编辑表格?手机wps编辑表格的方法
  16. 2022-04-13 Ambient Light Proximity Sensor 光感和距离传感器 STK3311X调试记录 RK3566 Android11平台
  17. 骏马淘金~~网赚不走弯路
  18. jsp四大作用域和九大内置对象
  19. 网络通信——下载管理器DownloadManager——在通知栏显示下载进度
  20. RFID读写器的组成

热门文章

  1. epplus word html,EPPlus简介
  2. bootstrap 步骤条_无骨香酥炸鸡柳,做法原来如此简单,3个关键步骤,学会可以开店...
  3. CSS百分比实现高度占位自适应
  4. mooc中的习题--然后是几点
  5. 雇员类(JAVA实现简单的类)
  6. 2018北京ICPC H. Approximate Matching(AC自动机+DP)
  7. OPNET网络仿真分析-目 录
  8. python分布式多进程框架 Ray
  9. python机器学习库keras——CNN卷积神经网络识别手写体
  10. jquery基本选择器:id选择器、class选择器、标签选择器、通配符选择器