设计模式-组合模式(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.问题 ...
随机推荐
- 【文文殿下】 [USACO08MAR]土地征用 题解
题解 斜率优化裸题. 有个很玄学的事情,就是我用\(f[i]=min\{f[j-1]+p[j].y*p[i].x\}\) 会很奇怪的Wa . 明明和\(f[i]=min\{f[j]+p[j+1].y* ...
- jzoj4235 序列
取前50個數暴力即可 #include<bits/stdc++.h> using namespace std; int n,m,a[100010],q[5]; int main(){ sc ...
- IE6下javascript:void(0)不可用的解决
<a href="javascript:void(0)" class="inp_sear_a" onclick="doSubmit();&quo ...
- Spring static 静态属性注入
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> &l ...
- C# 开发代码标准
开发标准文件 文件名称:C#开发规范 版 本:V2.0 前言 目的是为了规范每个人的编程风格,为确保系统源程序可读性,从而增强系统可维护性,制定下述编程规范,以规范系统各部分编程.系统继承的其它资源中 ...
- 设置 Linux 下打印机的几种方式
设置 Linux 下打印机的几种方式 一.使用 cups 进行设置 如若遇到 cups 也没有驱动的话可以前往 openprinting.org 找寻对应驱动. 二.前往 official 下载驱动 ...
- SQLYog执行SQL脚本提示:错误代码: 1067 - Invalid default value for '数据库表'查询:解决办法
强烈建议:完全卸载当前版本MySQL,重新安装5.6及以上版本 完全卸载方法:https://jingyan.baidu.com/article/3d69c551611290f0ce02d77b.ht ...
- [Leetcode]931.下降路径最小和
题目链接 这一题目首先需要弄懂题目的意思,下降路径最小和指的是在方阵中可以从上往下行走,走过后获得的值最小,方向可以是走左下,右下,直下. 题目和传统的动态规划一样,把边界的值先初始化,然后通过状态转 ...
- Nutch抓取流程
nutch抓取流程注入起始url(inject).生成爬取列表(generate).爬取(fetch).解析网页内容(parse).更新url数据库(updatedb)1:注入起始url(inject ...
- mysql基础知识(3)
十六.组合查询 使用 union 来组合查询,如果第一个查询返回M行,第二个查询返回N行,那么组合查询的结果一般为 M+N 行. 注意:每个查询必须包含相同的行.表达式的聚集函数:默认会去除相同行.表 ...