设计模式之Composite(组合)模式
1、出现原因
1、在面向对象系统中,我们常会遇到一类具有“容器”特征的对象——即它们在充当对象的同时,又是其他对象的容器。
如何将“客户代码与复杂的对象容器结构”解耦(将这种组合容器对象设计成树形结构,从而可以对下面所有的容器都可以通过最上层 的根对象 实现 统一 的调用,进而客户端就不在乎 其内部是怎么实现的,耦合 降低了)?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
2、意图
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。(通过 树根对象的 执行方法,从而调用 他下面的所有的子节点)
3、结构图
4、代码演示
业务实现:
- /// <summary>
- /// 抽象的统一 入口
- /// </summary>
- public abstract class AbsCompany
- {
- protected string Name { set; get; }
- public AbsCompany(string str)
- {
- this.Name = str;
- }
- public abstract void Add(AbsCompany item);
- public abstract void Remove(AbsCompany item);
- public abstract void Show();
- public abstract void DoDuty();
- //增加子节点的 方式可以 设置 父节点属性
- public AbsCompany Father { set; get; }
- }
- /// <summary>
- /// 叶子节点1
- /// </summary>
- public class HRPart : AbsCompany
- {
- public HRPart(string name)
- : base(name)
- {
- }
- //叶子节点不能实现 增删节点操作
- public override void Add(AbsCompany item)
- {
- throw new InvalidOperationException("叶子节点不允许操作");
- }
- public override void Remove(AbsCompany item)
- {
- throw new InvalidOperationException("叶子节点不允许操作");
- }
- public override void Show()
- {
- Console.WriteLine("人力资源部:"+base.Name);
- }
- public override void DoDuty()
- {
- Console.WriteLine(base.Name+":致力于招募人才");
- }
- }
- /// <summary>
- /// 叶子节点2
- /// </summary>
- public class MoneyPart : AbsCompany
- {
- public MoneyPart(string name)
- : base(name)
- {
- }
- //叶子节点不能实现 增删节点的操作
- public override void Add(AbsCompany item)
- {
- throw new InvalidOperationException("叶子节点不允许操作");
- }
- public override void Remove(AbsCompany item)
- {
- throw new InvalidOperationException("叶子节点不允许操作");
- }
- public override void Show()
- {
- Console.WriteLine("财务部分:"+base.Name);
- }
- public override void DoDuty()
- {
- Console.WriteLine(base.Name+":致力于管理好公司的财务");
- }
- }
- /// <summary>
- /// 树形节点(Composite)
- /// </summary>
- public class Company : AbsCompany
- {
- public Company(string name)
- : base(name)
- {
- }
- //对应 上级节点是 聚合关系
- private List<AbsCompany> items = new List<AbsCompany>();
- public override void Add(AbsCompany item)
- {
- items.Add(item);
- //父节点方式:增加子节点
- item.Father = this;
- }
- public override void Remove(AbsCompany item)
- {
- items.Remove(item);
- //父节点 方式 :删除子节点:
- item.Father = null;//此节点没有父节点了,因此它的父节点下面就没有这个子节点了
- }
- /// <summary>
- /// 实现了加载 次节点下面的所有节点:递归
- /// (**)调用的顺序:当 调用到一个子节点,会将他的下面 子节点全都调用完成之后,才调用他的兄弟节点
- /// </summary>
- /// <param name="item"></param>
- public override void Show()
- {
- //先显示自己
- Console.WriteLine("公司名称:"+base.Name);
- //显示下面所有的子节点的 名称
- foreach (var item in items)
- {
- item.Show();
- }
- //注意:要是使用 父节点的方式 实现树形组合:这个时候递归遍历下面所有的子节点的方式就不能执行了
- }
- public override void DoDuty()
- {
- //先执行自己的职责
- Console.WriteLine(base.Name+":致力于管理好整个公司");
- //在执行 他的节点下面的所有的节点的 所有的职责
- foreach (var item in items)
- {
- item.DoDuty();
- }
- }
- }
Composite模式
客户端调用代码:
- //都是通过AbsCompany,后面创建的过程 可以通过 反射进行创建。所以客户 就可以直接 通过树形节点的 最顶层节点 就行创建下面一系列的节点,不用关心具体的实现 (耦合 大大降低)
- AbsCompany HeadCompany = new Company("阿里巴巴");
- AbsCompany hr1 = new HRPart("总公司人力资源部");
- AbsCompany money1 = new MoneyPart("总公司财务部");
- AbsCompany company1 = new Company("上海分公司");
- AbsCompany company2 = new Company("北京办事处");
- AbsCompany hr2 = new HRPart("上海分公司人力资源部");
- AbsCompany money2 = new MoneyPart("上海分公司财务部");
- AbsCompany hr3 = new HRPart("北京人力资源部");
- AbsCompany money3 = new MoneyPart("北京财务部门");
- AbsCompany company3 = new Company("深圳办事处");
- AbsCompany hr4 = new HRPart("深圳人力资源部");
- AbsCompany money4 = new MoneyPart("深圳财务部");
- HeadCompany.Add(company1);
- HeadCompany.Add(hr1);
- HeadCompany.Add(money1);
- company1.Add(hr2);
- company1.Add(money2);
- company1.Add(company2);
- company1.Add(company3);
- company2.Add(hr3);
- company2.Add(money3);
- company3.Add(hr4);
- company3.Add(money4);
- HeadCompany.Show();
- HeadCompany.DoDuty();
客户端调用代码
每个对象的创建可以通过反射的方式进行创建
5、实现Composite模式两种方式
透明方式和安全模式
7、适用性
两个或者多个类有相似的形式,或者共同代表某个完整的概念,(所有的类都有几乎相同的成员,并且叶子节点可以含有多个)外界的用户也希望他们合而为一(通过一个抽象的基类和接口 就可以 指向所有的类,用户不用关心具体的实现),就可以把这几个类“组合”起来,成为一个新的类,用户只需要调用这个新的类就可以了。
8、总结
1、Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。(因为这些对象都有几乎相同的结构,所以可以通过抽象基类或接口 进行 调用)
2、将“客户代码与复杂的对象容器结构”解耦(因为所有的类含有 几乎相同的 结构,所以可以通过抽象基类或 接口进行调用,所以用户 只需直接 调用,不许关心 其内部是怎么实现的,耦合大大降低)是Composite模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的内部实现结构——发生依赖关系,从而更能“应对变化”。(客户端和抽象接口发生依赖关系)
3、Composite模式中,是将“Add和Remove等和对象容器相关的方法”定义在“表示抽象对象的Component类”中,还是将其定义在“表示对象容器的Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡。这里有可能违背面向对象的“单一职责原则”(基于透明性:则违背;基于安全性:则遵守),但是对于这种特殊结构,这又是必须付出的代价。
4、Composite模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。
5、Composite模式一般都 和 Builder 模式组合起来使用(Builder模式:http://www.cnblogs.com/xiaoxiaogogo/p/3572618.html),每个对象的创建通过Builder模式进行创建(将表示和创建隔离,达到解耦的目的)
设计模式之Composite(组合)模式的更多相关文章
- 设计模式(9)--Composite(组合模式)--结构型
1.模式定义: 组合模式属于对象的结构模式,有时又叫做“部分——整体”模式.组合模式将对象组织到树结构中,可以用来描述整体与部分的关系.组合模式可以使客户端将单纯元素与复合元素同等看待. 2.模式特点 ...
- 设计模式之——Composite组合模式
上周面试,面试官问桥接模式是什么,我就举了个例子:手机分为苹果,小米....,每个手机都有视频,游戏...等功能.直观上是一个树形结构.这种情况下,可以用桥接模式,把手机作为接口,苹果,小米等继承手机 ...
- 设计模式08: Composite 组合模式(结构型模式)
Composite 组合模式(结构型模式) 对象容器的问题在面向对象系统中,我们常会遇到一类具有“容器”特征的对象——即他们在充当对象的同时,又是其他对象的容器. public interface I ...
- 一天一个设计模式——Composite组合模式
一.模式说明 能够使容器与内容物具有一致性,创造出递归结构的模式就是Composite组合模式. 举个例子:计算机中的文件系统中有文件和文件夹的概念,我们知道,文件夹可以包含文件,也可以包含子文件夹, ...
- C++设计模式-Composite组合模式
Composite组合模式作用:将对象组合成树形结构以表示“部分-整体”的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. UML图如下: 在Component中声明所有用来 ...
- 十一、Composite 组合模式
原理: 代码清单 Entity public abstract class Entry { public abstract String getName(); public abstract int ...
- java23种设计模式——八、组合模式
目录 java23种设计模式-- 一.设计模式介绍 java23种设计模式-- 二.单例模式 java23种设计模式--三.工厂模式 java23种设计模式--四.原型模式 java23种设计模式-- ...
- Composite组合模式(结构型模式)
1.概述 在面向对象系统中,经常会遇到一些具有"容器性质"的对象,它们自己在充当容器的同时,也充当其他对象的容器. 2.案例 需要构建一个容器系统,需要满足以下几点要求: (1). ...
- 设计模式学习之组合模式(Composite,结构型模式)(10)
转载地址:http://www.cnblogs.com/zhili/p/CompositePattern.html 一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系 ...
- 设计模式之:组合模式(Composite)
支持原创:http://blog.csdn.net/hguisu/article/details/7530783 设计模式(七)组合模式Composite(结构型) 1. 概述 在数据结构里面,树结构 ...
随机推荐
- (笔记)angular 的hover事件
- Chrome不能登录和同步的解决方法
打开 C:\Windows\System32\drivers\etc 下的 hosts文件 #SmartHosts START #Google Services START .docs.google. ...
- 支持在安卓中UI(View)的刷新功能
这是一款可以支持在安卓中UI(View)的刷新功能,Android中对View的更新有很多种方式,使用时要区分不同的应用场合.我感觉最要紧的是分清:多线程和双缓冲的使用情况. 现在可以尝试理解下 ...
- Elasticsearch的PHP的API使用(一)
前提:在服务器上安装Elasticsearch (host:192.168.1.10) http://192.168.1.10:9200?_search?pretty 1:安装PHP的Elast ...
- JavaScript中this详解
这里的主题是 this ,不扯远了.this 本身原本很简单,总是指向类的当前实例,this 不能赋值.这前提是说 this 不能脱离 类/对象 来说,也就是说 this 是面向对象语言里常见的一个关 ...
- 在VS中快速查看文件被谁签出
步骤如下: 1 在VS中的菜单上单击鼠标右键,然后选择显示“源代码管理” 2 选中要查看的文件后,在源代码管理中单击“属性” 3 打开第2个标签页“Check Out Status”,可以看到签出人等 ...
- Git一张图学习
- Lucene全文检索框架
1.什么时Lucene? 是一个全文搜索框架,而不是应用产品,他只是一种工具让你能实现某些产品,并不像www.baidu.com拿来就能用 是apache组织的一个用java实现的全文搜索引擎的开源项 ...
- [译]Memory Reordering Caught in the Act
原文:http://preshing.com/20120515/memory-reordering-caught-in-the-act/ 编写lock-free的C/C++程序时,在保证memory ...
- jquery不熟悉的方法
1.jquery有一个筛选api find. 语法很简单,比如: HTML 代码: <p><span>Hello</span>, how are you?</ ...