设计模式-组合模式(Composite)
一、概念
将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
二、模式动机
组合模式,通过设计一个抽像的组件类,使它既代表叶子对象,又代表组合对象,将叶子对象和组合对象统一起来。使得客户端在操作时不再区分当前操作的是叶子对象还是组合对象,而是以一个统一方式来操作。
三、模式的结构

示意代码如下:
package composite.structure; /**
* 统一叶子和组件的抽象构件类
* @ClassName: Component
* @author beteman6988
* @date 2017年11月29日 下午10:48:18
*
*/
public abstract class Component { /**
* 叶子和树技构件都具备的商业逻辑
* @Title: sampleOperation
* @param
* @return void
* @throws
*/
public abstract void sampleOperation(); /**
* 向组合对象中添加组件对象
* @Title: addChild
* @param @param child
* @return void
* @throws
*/
public abstract void addChild(Component child); /**
* 向组合对象中删除组件对象
* @param child
* @roseuid 5A1EC291037D
*/
public abstract void removeChild(Component child) ; /**
* 从组合对象中取出第index个位置的组件对象
* @param index
* @return Component
* @roseuid 5A1EC2F2011B
*/
public abstract Component getChildren(Integer index) ;
}
package composite.structure; import java.util.ArrayList;
import java.util.List; /**
* 组合对像,通常存储子组件对象,实现抽象组件里面定义的与操作子组件对象有关的行为。
* @ClassName: Composite
* @author beteman6988
* @date 2017年12月3日 上午9:22:08
*
*/
public class Composite extends Component { List<Component> childComponent=new ArrayList<Component>(); /**
* 商业逻辑,这里样例迭代所有子组件的该方法
*/
@Override
public void sampleOperation() {
for(Component component:childComponent) {
component.sampleOperation();
} } @Override
public void addChild(Component child) {
this.childComponent.add(child);
} @Override
public void removeChild(Component child) {
this.childComponent.remove(child);
} @Override
public Component getChildren(Integer index) {
if(!childComponent.isEmpty() && childComponent.size()>index ) {
return this.childComponent.get(index);
}
return null;
} }
package composite.structure; /**
* 叶子组件对象
* @ClassName: Leaf
* @author beteman6988
* @date 2017年12月3日 上午9:25:42
*
*/
public class Leaf extends Component { /**
* 商业逻辑
*/
@Override
public void sampleOperation() {
//具体的商业逻辑
} /**
* 由于是叶子对象节点,不具备增加组件对象的功能,所以可以提供平庸实现
*/
@Override
public void addChild(Component child) { } /**
* 由于是叶子对象节点,不具备删除组件对象的功能,所以可以提供平庸实现
*/
@Override
public void removeChild(Component child) {
// TODO Auto-generated method stub } /**
* 由于是叶子对象节点,不具获取子组件对象的功能,所以可以提供平庸实现
*/
@Override
public Component getChildren(Integer index) {
// TODO Auto-generated method stub
return null;
} }
角色说明:
Component:抽象的组件对象,可以是一个抽象类或者是一个接口,它既代表叶子对象,也代组合对象,让客户端通过这个接口来管理整个对象结构,上面的样例代码定义的是一个抽象类,且管理组合对象的方法是抽象的,其实也可以提供默认的实现。不提供默认实现的好处就是叶子对象针对这些不支持的行为必须给出明确的处理方式。提供默认形为的好处,如果默认的是针对叶子对象的行为,那么针对叶子对象就不需要对这些不支持的形为提供明确的处理方式。并没有说哪种就好哪种就劣,各有优缺。
Composite:组合对象,通常存储子组件,并包含操作子组件的具体行为,如对子组件进行增删改查。
Leaf:叶子节点组件:定义和实现与叶子对象的行为,不能包含其它子组件。
在组合模式中,对象分为两种,一为Composite对象,它可以包含其它的Composite或叶子对象,就像一个容器,二为不能包含子组件的Leaf对象。对于Composite对像,为了管理子组件对象,就要定以一些管理子组件的操作行为,以上的例 子中将这些操作形为定义在了抽象的Component组件中,但是这些行为其实对于Leaf对象是没有意义的,这些行为可以放在Composite中,而非放在在Component中。所以跟据Composite对象中管理子组件的行为操作是放在Componnet或是Composite中,细分为了“透明模式”和“安全模式”
透明模式:上面的示例结构为透明模式,透明模式对于客户端来说,Leaf对象和Composite对象具有相同的行为,对于客户端而言,Leaf对角和Composite对象是透明的,他们都是Component对象,具有相同的接口行为,也可以在Leaf对象上使用增加子组件的行为,只是这些行为对于Leaf对象是无意义的,这也意为着是不安全的。
安全模式:针对透明模式中,管理子组件的行为如果不定义在Component中,而是定义在Composite中,这样对于Leaf对象就是安全的了。因为客户端对于Leaf对象,就无在调用管理子组件的行为。模式结构如下:

示意代码如下:
package composite.structure.safety; /**
* 统一叶子和组件的抽象构件类
* @ClassName: Component
* @author beteman6988
* @date 2017年11月29日 下午10:48:18
*
*/
public abstract class Component { /**
* 叶子和树技构件都具备的商业逻辑
* @Title: sampleOperation
* @param
* @return void
* @throws
*/
public abstract void sampleOperation(); }
package composite.structure.safety; import java.util.ArrayList;
import java.util.List; /**
* 组合对像,通常存储子组件对象,实现抽象组件里面定义的与操作子组件对象有关的行为。
* @ClassName: Composite
* @author beteman6988
* @date 2017年12月3日 上午9:22:08
*
*/
public class Composite extends Component { List<Component> childComponent=new ArrayList<Component>(); /**
* 商业逻辑,这里样例迭代所有子组件的该方法
*/
@Override
public void sampleOperation() {
for(Component component:childComponent) {
component.sampleOperation();
}
} /**
* 向组合对象中添加组件对象
* @Title: addChild
* @param @param child
* @return void
* @throws
*/
public void addChild(Component child) {
this.childComponent.add(child);
} /**
* 向组合对象中删除组件对象
* @Title: removeChild
* @param @param child
* @return void
* @throws
*/
public void removeChild(Component child) {
this.childComponent.remove(child);
} /**
* 从组合对象中取出第index个位置的组件对象
* @Title: getChildren
* @param @param index
* @param @return
* @return Component
* @throws
*/
public Component getChildren(Integer index) {
if(!childComponent.isEmpty() && childComponent.size()>index ) {
return this.childComponent.get(index);
}
return null;
} }
package composite.structure.safety; /**
* 叶子组件对象
* @ClassName: Leaf
* @author beteman6988
* @date 2017年12月3日 上午9:25:42
*
*/
public class Leaf extends Component { /**
* 商业逻辑
*/
@Override
public void sampleOperation() {
//具体的商业逻辑
} }
四、模式样例
打印出以常见学的学校组织架构为例,如下:
XX大学
信息工程学院
计算机科学系
电子与信息工程系
建筑工程学院
土木建筑系
工程管理系
透明模式:

package composite.sample; /**
* 院系抽像接口
* @ClassName: SCCompent
* @author beteman6988
* @date 2017年12月9日 下午8:15:46
*
*/
public interface SCComponent { /**
* get院系名称
* @Title: getName
* @param @return
* @return String
* @throws
*/
public String getName(); /**
* 设置院系名称
* @Title: setName
* @param @return
* @return
* @throws
*/
public void setName(String name); /**
* 添加下级院系
* @Title: addSCc
* @param @param scComponent
* @return void
* @throws
*/
public void addSCc(SCComponent scComponent); /**
* 移去下级院系
* @Title: removeSCc
* @param @param scComponent
* @return void
* @throws
*/
public void removeSCc(SCComponent scComponent); /**
* 打印院系名称
* @Title: printName
* @param @param preStr
* @return void
* @throws
*/
public void printName(String preStr); }
package composite.sample; /**
* 叶子系节点
* @ClassName: Department
* @author beteman6988
* @date 2017年12月9日 下午8:25:53
*
*/
public class Department implements SCComponent { private String departmentName; @Override
public String getName() {
// TODO Auto-generated method stub
return departmentName;
} @Override
public void setName(String name) {
this.departmentName=name;
} @Override
public void addSCc(SCComponent scComponent) {
System.out.println("Department不支持addSCc行为!");
} @Override
public void removeSCc(SCComponent scComponent) {
System.out.println("Department不支持removeSCc行为!"); } @Override
public void printName(String preStr) {
System.out.println(preStr+this.departmentName);
} }
package composite.sample; import java.util.ArrayList;
import java.util.List; /**
*院系设置的组合对象
* @ClassName: SCComposite
* @author beteman6988
* @date 2017年12月9日 下午8:37:44
*
*/
public class SCComposite implements SCComponent { private String name; private List<SCComponent> sCCList=new ArrayList<SCComponent>(); @Override
public String getName() {
return this.name;
} @Override
public void setName(String name) {
this.name=name;
} @Override
public void addSCc(SCComponent scComponent) {
if(sCCList.indexOf(scComponent)<0) {
sCCList.add(scComponent);
} } @Override
public void removeSCc(SCComponent scComponent) {
this.sCCList.remove(scComponent); } @Override
public void printName(String preStr) {
System.out.println(preStr+this.name);
for(SCComponent component:sCCList) {
component.printName(preStr+" ");
}
}
}
package composite.sample;
public class Client {
public static void main(String[] args) {
SCComponent head=new SCComposite();
head.setName("XX大学");
SCComponent sCCOne=new SCComposite();
sCCOne.setName("信息工程学院");
SCComponent sCCTwo=new SCComposite();
sCCTwo.setName("建筑工程学院");
head.addSCc(sCCOne);
head.addSCc(sCCTwo);
SCComponent dptOne=new Department();
dptOne.setName("计算机科学系");
SCComponent dptTwo=new Department();
dptTwo.setName("电子与信息工程系");
sCCOne.addSCc(dptOne);
sCCOne.addSCc(dptTwo);
SCComponent dptThree=new Department();
dptThree.setName("土木建筑系");
SCComponent dptFour=new Department();
dptFour.setName("工程管理系");
sCCTwo.addSCc(dptThree);
sCCTwo.addSCc(dptFour);
//sCCTwo.removeSCc(dptThree);
head.printName("");
}
}
运行结果如下:
XX大学
信息工程学院
计算机科学系
电子与信息工程系
建筑工程学院
工程管理系
安全模式:

代码如下:
package composite.sample.safety; /**
* 院系抽像接口
* @ClassName: SCCompent
* @author beteman6988
* @date 2017年12月9日 下午8:15:46
*
*/
public interface SCComponent { /**
* get院系名称
* @Title: getName
* @param @return
* @return String
* @throws
*/
public String getName(); /**
* 设置院系名称
* @Title: setName
* @param @return
* @return
* @throws
*/
public void setName(String name); /**
* 打印院系名称
* @Title: printName
* @param @param preStr
* @return void
* @throws
*/
public void printName(String preStr); }
package composite.sample.safety; /**
* 叶子系节点
* @ClassName: Department
* @author beteman6988
* @date 2017年12月9日 下午8:25:53
*
*/
public class Department implements SCComponent { private String departmentName; @Override
public String getName() {
// TODO Auto-generated method stub
return departmentName;
} @Override
public void setName(String name) {
this.departmentName=name;
} @Override
public void printName(String preStr) {
System.out.println(preStr+this.departmentName);
} }
package composite.sample.safety; import java.util.ArrayList;
import java.util.List; /**
*院系设置的组合对象
* @ClassName: SCComposite
* @author beteman6988
* @date 2017年12月9日 下午8:37:44
*
*/
public class SCComposite implements SCComponent { private String name; private List<SCComponent> sCCList=new ArrayList<SCComponent>(); @Override
public String getName() {
return this.name;
} @Override
public void setName(String name) {
this.name=name;
} public void addSCc(SCComponent scComponent) {
if(sCCList.indexOf(scComponent)<0) {
sCCList.add(scComponent);
} } public void removeSCc(SCComponent scComponent) {
this.sCCList.remove(scComponent); } @Override
public void printName(String preStr) {
System.out.println(preStr+this.name);
for(SCComponent component:sCCList) {
component.printName(preStr+" ");
}
}
}
package composite.sample.safety;
public class Client {
public static void main(String[] args) {
SCComposite head=new SCComposite();
head.setName("XX大学");
SCComposite sCCOne=new SCComposite();
sCCOne.setName("信息工程学院");
SCComposite sCCTwo=new SCComposite();
sCCTwo.setName("建筑工程学院");
head.addSCc(sCCOne);
head.addSCc(sCCTwo);
SCComponent dptOne=new Department();
dptOne.setName("计算机科学系");
SCComponent dptTwo=new Department();
dptTwo.setName("电子与信息工程系");
sCCOne.addSCc(dptOne);
sCCOne.addSCc(dptTwo);
SCComponent dptThree=new Department();
dptThree.setName("土木建筑系");
SCComponent dptFour=new Department();
dptFour.setName("工程管理系");
sCCTwo.addSCc(dptThree);
sCCTwo.addSCc(dptFour);
//sCCTwo.removeSCc(dptThree);
head.printName("");
}
}
运行结果如下:
XX大学
信息工程学院
计算机科学系
电子与信息工程系
建筑工程学院
土木建筑系
工程管理系
五、模式优缺点
优点:1.定义了包含基本对象和组合对象的类层次结构
2.统一了组合对象和叶子对象,在组合模式中,可以把叶子对象当成特殊的组合对象来看待,为他们定义统一的父类,从而把叶子对象和组合对象的行为统一起来。
3.方便扩展,只要是Component的子类对象,都可以很方便添加到组合对象中。
缺点:优点中的第3点既是优点,也是缺点,组合对象很难确定里面的具体组件类型,因为只要是Component的子类对象,都可以添加到组合对象中,所以当要确定组合对象中组件具体的类型时,就必须在运行期动态检测。
设计模式-组合模式(Composite)的更多相关文章
- 浅谈设计模式--组合模式(Composite Pattern)
组合模式(Composite Pattern) 组合模式,有时候又叫部分-整体结构(part-whole hierarchy),使得用户对单个对象和对一组对象的使用具有一致性.简单来说,就是可以像使用 ...
- 设计模式 - 组合模式(composite pattern) 迭代器(iterator) 具体解释
组合模式(composite pattern) 迭代器(iterator) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考组合模式(composit ...
- 设计模式组合模式(Composite)精华
23种子GOF设计模式一般分为三类:创建模式.结构模型.行为模式. 创建模式抽象的实例,他们帮助如何创建一个系统独立.这是一个这些对象和陈述的组合. 创建使用继承类的类架构更改实例.的对象类型模型的建 ...
- 设计模式 -- 组合模式 (Composite Pattern)
定义: 对象组合成部分整体结构,单个对象和组合对象具有一致性. 看了下大概结构就是集团总公司和子公司那种层级结构. 角色介绍: Component :抽象根节点:其实相当去总公司,抽象子类共有的方法: ...
- 设计模式--组合模式Composite(结构型)
一.概念 组合模式允许你将对象组合成树形结构来表现"整体/部分"层次结构.组合能让客户以一致的方式处理个别对象以及对象组合. 二.UML图 1.Component(对象接口),定义 ...
- C#设计模式——组合模式(Composite Pattern)
一.概述 在软件开发中,我们往往会遇上类似树形结构的对象体系.即某一对象既可能在树形结构中作为叶节点存在,也可能作为分支节点存在.比如在文件系统中,文件是作为叶节点存在,而文件夹就是分支节点.在设计这 ...
- 说说设计模式~组合模式(Composite)
返回目录 何时能用到它? 组合模式又叫部分-整体模式,在树型结构中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦.对于今天这个 ...
- 大话设计模式--组合模式 Composite -- C++实现实例
1. 组合模式: 将对象组合成树形结构以表示"部分--整体"的层次结构,组合模式使用户对单个对象和组合对象的使用具有一致性. 需求中是体现部分与整体层次的结构时,希望用户可以忽略组 ...
- 设计模式(七)组合模式Composite(结构型)
设计模式(七)组合模式Composite(结构型) 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 ...
随机推荐
- 《PHP, MySQL, Javascript和CSS》读书随手记----php篇
1. 基础 注释: // 或 /* */ $标示变量 语句末尾加分号 数组: $oxo = array(array('x','','o'), array('p','x',''),array('','x ...
- 【npm】详解npm的模块安装机制
依赖树表面的逻辑结构与依赖树真实的物理结构 依赖树表面的逻辑结构与依赖树真实的物理结构并不一定相同! 这里要先提到两个命令:tree -d(linux)和npm ls(npm) 在一个npm项目下 ...
- Python3.5 学习二十
学会用三种方法检索数据 1.对象方式 2.字典方式 3.元组方式 models后面,如果是.values() 则为字典方式 如果是value_list() 则为元组方式 跨表操作时,如果是对象,可以用 ...
- vue.js - 2
最近开发公司vue前端项目,做一下笔记,偶尔上来查漏补缺 组件操作: 使用flag标识符结合v-if和v-else切换组件 页面结构: <div id="app"> & ...
- [Ynoi2015]此时此刻的光辉(莫队)
一道神题...自己写出来以后被卡常了...荣获洛谷最差解... 思路还是比较好想,对于每个数 \(\sqrt{n}\) 分块,对于 \(\sqrt{n}\) 以内的数,我们可以直接求出来.对于 \(\ ...
- 【kuangbin专题】计算几何_半平面交
1.poj3335 Rotating Scoreboard 传送:http://poj.org/problem?id=3335 题意:就是有个球场,球场的形状是个凸多边形,然后观众是坐在多边形的边上的 ...
- 开发创建XMPP“发布订阅”扩展(xmpp pubsub extend)
发布订阅(PubSub)是一个功能强大的XMPP协议扩展.用户订阅一个项目(在xmpp中叫做node),得到通知时,也即当事项节点更新时.xmpp服务器通知用户(通过message格式). 节点类型: ...
- 理解WSGI
WSGI是什么? WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是为 Python 语言定义 ...
- h5 端图片上传-模拟多张上传
1.由于后端的限制,上传图片到服务器只能的一张一张传2.显示图片预览是本地的图片3.根据服务器返回的结果拿到相应的路径保存到提交评论的接口中4.删除的时候,需要删除对应的路径,不要把删除的提交到评论的 ...
- android app性能优化大汇总
这里根据网络上各位大神已经总结的知识内容做一个大汇总,作为记录,方便后续“温故知新”. 性能指标: (1)使用流畅度: 图片处理器每秒刷新的帧数(FPS),可用来指示页面是否平滑的渲染.高的帧率可以 ...