合成模式属于对象的结构模式,有时又叫做“部分——整体”模式。合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式可以使客户端将单纯元素与复合元素同等看待。

合成模式

合成模式把部分和整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由它们复合而成的合成对象同等看待。

比如,一个文件系统就是一个典型的合成模式系统。下图是常见的计算机XP文件系统的一部分。

从上图可以看出,文件系统是一个树结构,树上长有节点。树的节点有两种,一种是树枝节点,即目录,有内部树结构,在图中涂有颜色;另一种是文件,即树叶节点,没有内部树结构。

显然,可以把目录和文件当做同一种对象同等对待和处理,这也就是合成模式的应用。

合成模式可以不提供父对象的管理方法,但是合成模式必须在合适的地方提供子对象的管理方法,诸如:add()、remove()、以及getChild()等。

合成模式的实现根据所实现接口的区别分为两种形式,分别称为安全式和透明式。

安全式合成模式的结构

安全模式的合成模式要求管理聚集的方法只出现在树枝构件类中,而不出现在树叶构件类中。

这种形式涉及到三个角色:

●  抽象构件(Component)角色:这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。合成对象通常把它所包含的子对象当做类型为Component的对象。在安全式的合成模式里,构件角色并不定义出管理子对象的方法,这一定义由树枝构件对象给出。

●  树叶构件(Leaf)角色:树叶对象是没有下级子对象的对象,定义出参加组合的原始对象的行为。

●  树枝构件(Composite)角色:代表参加组合的有下级子对象的对象。树枝构件类给出所有的管理子对象的方法,如add()、remove()以及getChild()。

源代码

抽象构件角色类

public interface Component {

/**

* 输出组建自身的名称

*/

public void printStruct(String preStr);

}

树枝构件角色类

public class Composite implements Component {

/**

* 用来存储组合对象中包含的子组件对象

*/

private List childComponents = new ArrayList();

/**

* 组合对象的名字

*/

private String name;

/**

* 构造方法,传入组合对象的名字

* @param name 组合对象的名字

*/

public Composite(String name){

this.name = name;

}

/**

* 聚集管理方法,增加一个子构件对象

* @param child 子构件对象

*/

public void addChild(Component child){

childComponents.add(child);

}

/**

* 聚集管理方法,删除一个子构件对象

* @param index 子构件对象的下标

*/

public void removeChild(int index){

childComponents.remove(index);

}

/**

* 聚集管理方法,返回所有子构件对象

*/

public List getChild(){

return childComponents;

}

/**

* 输出对象的自身结构

* @param preStr 前缀,主要是按照层级拼接空格,实现向后缩进

*/

@Override

public void printStruct(String preStr) {

// 先把自己输出

System.out.println(preStr + "+" + this.name);

//如果还包含有子组件,那么就输出这些子组件对象

if(this.childComponents != null){

//添加两个空格,表示向后缩进两个空格

preStr += " ";

//输出当前对象的子对象

for(Component c : childComponents){

//递归输出每个子对象

c.printStruct(preStr);

}

}

}

}

树叶构件角色类

public class Leaf implements Component {

/**

* 叶子对象的名字

*/

private String name;

/**

* 构造方法,传入叶子对象的名称

* @param name 叶子对象的名字

*/

public Leaf(String name){

this.name = name;

}

/**

* 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字

* @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进

*/

@Override

public void printStruct(String preStr) {

// TODO Auto-generated method stub

System.out.println(preStr + "-" + name);

}

}

客户端类

public class Client {

public static void main(String[]args){

Composite root = new Composite("服装");

Composite c1 = new Composite("男装");

Composite c2 = new Composite("女装");

Leaf leaf1 = new Leaf("衬衫");

Leaf leaf2 = new Leaf("夹克");

Leaf leaf3 = new Leaf("裙子");

Leaf leaf4 = new Leaf("套装");

root.addChild(c1);

root.addChild(c2);

c1.addChild(leaf1);

c1.addChild(leaf2);

c2.addChild(leaf3);

c2.addChild(leaf4);

root.printStruct("");

}

}

可以看出,树枝构件类(Composite)给出了addChild()、removeChild()以及getChild()等方法的声明和实现,而树叶构件类则没有给出这些方法的声明或实现。这样的做法是安全的做法,由于这个特点,客户端应用程序不可能错误地调用树叶构件的聚集方法,因为树叶构件没有这些方法,调用会导致编译错误。

安全式合成模式的缺点是不够透明,因为树叶类和树枝类将具有不同的接口。

透明式合成模式的结构

与安全式的合成模式不同的是,透明式的合成模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定接口。

源代码

抽象构件角色类

public abstract class Component {

/**

* 输出组建自身的名称

*/

public abstract void printStruct(String preStr);

/**

* 聚集管理方法,增加一个子构件对象

* @param child 子构件对象

*/

public void addChild(Component child){

/**

* 缺省实现,抛出异常,因为叶子对象没有此功能

* 或者子组件没有实现这个功能

*/

throw new UnsupportedOperationException("对象不支持此功能");

}

/**

* 聚集管理方法,删除一个子构件对象

* @param index 子构件对象的下标

*/

public void removeChild(int index){

/**

* 缺省实现,抛出异常,因为叶子对象没有此功能

* 或者子组件没有实现这个功能

*/

throw new UnsupportedOperationException("对象不支持此功能");

}

/**

* 聚集管理方法,返回所有子构件对象

*/

public List getChild(){

/**

* 缺省实现,抛出异常,因为叶子对象没有此功能

* 或者子组件没有实现这个功能

*/

throw new UnsupportedOperationException("对象不支持此功能");

}

}

树枝构件角色类,此类将implements Conponent改为extends Conponent,其他地方无变化。

public class Composite extends Component {

/**

* 用来存储组合对象中包含的子组件对象

*/

private List childComponents = new ArrayList();

/**

* 组合对象的名字

*/

private String name;

/**

* 构造方法,传入组合对象的名字

* @param name 组合对象的名字

*/

public Composite(String name){

this.name = name;

}

/**

* 聚集管理方法,增加一个子构件对象

* @param child 子构件对象

*/

public void addChild(Component child){

childComponents.add(child);

}

/**

* 聚集管理方法,删除一个子构件对象

* @param index 子构件对象的下标

*/

public void removeChild(int index){

childComponents.remove(index);

}

/**

* 聚集管理方法,返回所有子构件对象

*/

public List getChild(){

return childComponents;

}

/**

* 输出对象的自身结构

* @param preStr 前缀,主要是按照层级拼接空格,实现向后缩进

*/

@Override

public void printStruct(String preStr) {

// 先把自己输出

System.out.println(preStr + "+" + this.name);

//如果还包含有子组件,那么就输出这些子组件对象

if(this.childComponents != null){

//添加两个空格,表示向后缩进两个空格

preStr += " ";

//输出当前对象的子对象

for(Component c : childComponents){

//递归输出每个子对象

c.printStruct(preStr);

}

}

}

}

树叶构件角色类,此类将implements Conponent改为extends Conponent,其他地方无变化。

public class Leaf extends Component {

/**

* 叶子对象的名字

*/

private String name;

/**

* 构造方法,传入叶子对象的名称

* @param name 叶子对象的名字

*/

public Leaf(String name){

this.name = name;

}

/**

* 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字

* @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进

*/

@Override

public void printStruct(String preStr) {

// TODO Auto-generated method stub

System.out.println(preStr + "-" + name);

}

}

客户端类的主要变化是不再区分Composite对象和Leaf对象。

public class Client {

public static void main(String[]args){

Component root = new Composite("服装");

Component c1 = new Composite("男装");

Component c2 = new Composite("女装");

Component leaf1 = new Leaf("衬衫");

Component leaf2 = new Leaf("夹克");

Component leaf3 = new Leaf("裙子");

Component leaf4 = new Leaf("套装");

root.addChild(c1);

root.addChild(c2);

c1.addChild(leaf1);

c1.addChild(leaf2);

c2.addChild(leaf3);

c2.addChild(leaf4);

root.printStruct("");

}

}

可以看出,客户端无需再区分操作的是树枝对象(Composite)还是树叶对象(Leaf)了;对于客户端而言,操作的都是Component对象。

两种实现方法的选择

这里所说的安全性合成模式是指:从客户端使用合成模式上看是否更安全,如果是安全的,那么就不会有发生误操作的可能,能访问的方法都是被支持的。

这里所说的透明性合成模式是指:从客户端使用合成模式上,是否需要区分到底是“树枝对象”还是“树叶对象”。如果是透明的,那就不用区分,对于客户而言,都是Compoent对象,具体的类型对于客户端而言是透明的,是无须关心的。

对于合成模式而言,在安全性和透明性上,会更看重透明性,毕竟合成模式的目的是:让客户端不再区分操作的是树枝对象还是树叶对象,而是以一个统一的方式来操作。

而且对于安全性的实现,需要区分是树枝对象还是树叶对象。有时候,需要将对象进行类型转换,却发现类型信息丢失了,只好强行转换,这种类型转换必然是不够安全的。

因此在使用合成模式的时候,建议多采用透明性的实现方式。

java composite 模式_《JAVA设计模式》中的组合模式Composite相关推荐

  1. 虚无空间java下载_Java进阶篇设计模式之二 ----- 工厂模式

    前言 在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模 ...

  2. 再战设计模式(九)之组合模式

    组合模式 工作流程分析 组合模式为处理树形结构提供了完美的解决方案,描述了如何将容器和叶子进行递归组合,使得用户在使用时可以一致性的对待容器和叶子 当容器对象的指定方法被调用时,将遍历整个树形结构,寻 ...

  3. 设计模式(17)之组合模式

    一.前言 在现实生活中,存在很多"部分-整体"的关系,例如,大学中的部门与学院.总公司中的部门与分公司.学习用品中的书与书包.生活用品中的衣服与衣柜.以及厨房中的锅碗瓢盆等.在软件 ...

  4. 《研磨设计模式》chap15 组合模式(2)改写示例+总结

    1. 改写示例 在添加子组件的方法实现中,加入对父组件的引用实现.在删除子组件的方法实现中,加入把被删除的商品类别对象的父商品类别,设置成为被删除的商品类别的子类别的父商品类别的功能.实现新的返回组件 ...

  5. php 组合模式,php设计模式(十三)透明组合模式

    组合模式用来解决整体和部分可以一致对待的问题: 比如说 文件夹 和其下的 文件: 可以复制文件也可以复制整个文件夹: 组合模式是将对象组合成树形结构以表示整体和部分的层次结构: 可以方便的增加节点: ...

  6. 第11课:生活中的组合模式——自己组装电脑

    用程序来模拟生活 从剧情中思考组合模式 组合模式的模型抽象 类图 模型说明 组合模式的优点 组合模式的缺点 应用场景 [故事剧情] Tony 用的笔记本电脑还是大学时候买的,到现在已经用了5年,虽然后 ...

  7. 学习组合模式,转载一段有关组合模式的详解

                   学习组合模式,转载一段有关组合模式的详解,从定义中可以看出,组合模式用来表示部分与整体的层次结构(类似于树结构),而且也可以使用户对单个对象(叶子节点)以及组合对象( 飞 ...

  8. java设计模式组合模式详解_《JAVA设计模式》之组合模式(Composite)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述合成(Composite)模式的:html 合成模式属于对象的结构模式,有时又叫作"部分--总体"模式.合成模式将对象 ...

  9. java设计模式迭代器模式_迭代器设计模式示例

    java设计模式迭代器模式 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式 ...

  10. 工厂模式 java场景_研磨设计模式之简单工厂模式(场景问题)

    简单工厂不是一个标准的设计模式,但是它实在是太常用了,简单而又神奇,所以还是需要好好掌握的,就当是对学习设计模式的热身运动吧.为了保持一致性,我们尽量按照学习其它模式的步骤来进行学习. 1  场景问题 ...

最新文章

  1. oracle grand select,Oracle SQL 高级篇
  2. pandas使用drop_duplicates函数基于subset参数指定的数据列子集删除重复行、并设置keep参数保留重复行中的最后一个数据行
  3. 星梦缘陈彦妃_还记得《星梦缘》的女主吗,她现在变成这样了
  4. GDCM:gdcm::PDBHeader的测试程序
  5. .NET Core项目从xproj+project.json向csproj迁移简介
  6. 盖茨为什么会要求对机器人收税?
  7. 1. K近邻算法(KNN)
  8. python获取html文本框内容_Python3处理HTML获取所需内容
  9. 怎样写出没有bug的代码?
  10. 熊猫直播凉了,直播大战厮杀后只剩遍地鸡毛! | 畅言
  11. sitemesh 2.4 装饰器学习
  12. Sandbox简介和路径获取
  13. ArrayList 初学小结!
  14. dotnetbar 控件使用总结(一)
  15. win10很多软件显示模糊_Win7系统和Win10系统你会怎么选?
  16. AndroidStudio 集成 OpenCV
  17. 年轻人逃离一线城市:外地人生存环境愈发严峻
  18. 我读《写给大家看的设计书》
  19. 字节跳动Android内部学习资料泄露,高级面试题+解析
  20. Qt 数字报阅读器 图文版

热门文章

  1. Maybe it's time to go away
  2. 一个服务调用另一个服务的步骤
  3. Cannot detect Web Project version. Please specify version of Web Project through Maven project ...报错
  4. 【BZOJ】3963: [WF2011]MachineWorks
  5. Java_一致性哈希算法与Java实现
  6. (二):winelib用户手册1
  7. Postgresql中存储过程(函数)调用存储过程(函数)时应用注意的问题
  8. 数据结构期末复习第一章绪论
  9. 程序入口地址的直接定制表【 (1) 清屏(2) 设置前景色 (3) 设置背景色 (4) 向上滚动一行】...
  10. Refactoring Page Head