目录

一、基本概念

二、通俗解释

三、分类

1.安全式合成模式的结构

2.透明式合成模式的结构

四、两种实现方法的选择


一、基本概念

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

二、通俗解释

COMPOSITE合成模式:Mary今天过生日。“我过生日,你要送我一件礼物。”“嗯,好吧,去商店,你自己挑。”“这件T恤挺漂亮,买,这条裙子好看,买,这个包也不错,买。”“喂,买了三件了呀,我只答应送一件礼物的哦。”“什么呀,T恤加裙子加包包,正好配成一套呀,小姐,麻烦你包起来。”“……”,MM都会用Composite模式了,你会了没有? 合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。

文件系统例子:

合成模式把部分和整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由它们复合而成的合成对象同等看待。比如,一个文件系统就是一个典型的合成模式系统。下图是常见的计算机XP文件系统的一部分。

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

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

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

三、分类

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

1.安全式合成模式的结构

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

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

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

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

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

抽象构件角色类

public interface Component {/*** 输出组建自身的名称*/public void printStruct(String preStr);
}

树枝构件角色类

public class Composite implements Component {/*** 用来存储组合对象中包含的子组件对象*/private List<Component> childComponents = new ArrayList<Component>();/*** 组合对象的名字*/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<Component> getChild(){return childComponents;}/*** 输出对象的自身结构* @param preStr 前缀,主要是按照层级拼接空格,实现向后缩进*/@Overridepublic 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 前缀,主要是按照层级拼接的空格,实现向后缩进*/@Overridepublic void printStruct(String preStr) {// TODO Auto-generated method stubSystem.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()等方法的声明和实现,而树叶构件类则没有给出这些方法的声明或实现。这样的做法是安全的做法,由于这个特点,客户端应用程序不可能错误地调用树叶构件的聚集方法,因为树叶构件没有这些方法,调用会导致编译错误。

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

2.透明式合成模式的结构

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

抽象构件角色类

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<Component> getChild(){/*** 缺省实现,抛出异常,因为叶子对象没有此功能* 或者子组件没有实现这个功能*/throw new UnsupportedOperationException("对象不支持此功能");}
}

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

public class Composite extends Component {/*** 用来存储组合对象中包含的子组件对象*/private List<Component> childComponents = new ArrayList<Component>();/*** 组合对象的名字*/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<Component> getChild(){return childComponents;}/*** 输出对象的自身结构* @param preStr 前缀,主要是按照层级拼接空格,实现向后缩进*/@Overridepublic 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 前缀,主要是按照层级拼接的空格,实现向后缩进*/@Overridepublic void printStruct(String preStr) {// TODO Auto-generated method stubSystem.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与模式》之合成模式)

每天学习一个设计模式(三):结构型之合成模式相关推荐

  1. Java设计模式之结构型:桥接模式

    一.什么是桥接模式: 桥接,顾名思义,就是用来连接两个部分,使得两个部分可以互相通讯,桥接模式的作用就是为被分离的抽象部分和实现部分搭桥.在现实生活中一个物品在搭配不同的配件时会产生不同的动作和结果, ...

  2. Java设计模式之结构型:组合模式

    前言: 我们对于上面两幅图片肯定非常熟悉,这两幅图片我们都可以看做是一个文件结构,对于这样的结构我们称之为树形结构.在数据结构中我们知道可以通过调用某个方法来遍历整个树,当我们找到某个叶子节点后,就可 ...

  3. Java设计模式之结构型:外观模式

    一.什么是外观模式: 外观模式通过对客户端提供一个统一的接口,用于访问子系统中的一群接口.使用外观模式有以下几点好处: (1)更加易用:使得子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要 ...

  4. Java设计模式之结构型:代理模式

    前言: 我们一般在租房子时会去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做:再比如我们打官司需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们 ...

  5. 围观设计模式(16)--结构型之组合模式(Composite Pattern)

    组合模式也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系,其定义为:将对象组合成树形结构以表示"整体与部分"的层次结构,使得用户对单个对象和组合对象的使用具有 ...

  6. 设计模式之结构型(4)-桥接模式(Bridge)

    (一)定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化.(将一个对象多维度的变化分离) ① 桥接模式主要用意是为了实现抽象部分与实现部分脱耦,使它们各自可以独立变化. ② 在开发过程中通常会 ...

  7. Java设计模式之结构型:享元模式

    一.什么是享元模式: 享元模式通过共享技术有效地支持细粒度.状态变化小的对象复用,当系统中存在有多个相同的对象,那么只共享一份,不必每个都去实例化一个对象,极大地减少系统中对象的数量.比如说一个文本系 ...

  8. Java设计模式之结构型:装饰器模式

    一.什么是装饰器模式: 当需要对类的功能进行拓展时,一般可以使用继承,但如果需要拓展的功能种类很繁多,那势必会生成很多子类,增加系统的复杂性,并且使用继承实现功能拓展时,我们必须能够预见这些拓展功能, ...

  9. Java设计模式之结构型:适配器模式

    一.什么是适配器模式: 适配器模式主要用于将一个类的接口转化成客户端希望的目标类格式,使得原本不兼容的类可以在一起工作,将目标类和适配者类解耦:同时也符合"开闭原则",可以在不修改 ...

最新文章

  1. 科普长文揭秘生命为何会具有主观能动性
  2. ARM汇编:使用汇编语言进行数据访问时需要注意的几个问题
  3. Shrio Unable to execute ‘doFinal‘ with cipher instance
  4. 网页设计界面 电脑版设计
  5. 【VS开发】PCIe体系结构的组成部件
  6. Python助力期末
  7. Linux下备份cisco路由配置
  8. SAP UI5 OData框架里硬编码的80是怎么来的
  9. 实验一 201521410003 15网一 叶萌熙
  10. 数据挖掘导论课后习题答案-第二章
  11. python大数据论文_大数据环境下基于python的网络爬虫技术
  12. 社会性动物1: 从众的原因,如何避免
  13. polkitd进程解释
  14. 各种开发语言项目环境国内(中国国内加速镜像)配置教程和部分实践经验,包括github.com, nodejs,npm,nvm, yarn, java, maven, gradle, python, m
  15. java回顾:MyBatis开发、配置、标签、封装会话工具
  16. Excel教程视频《Excel大神上分攻略》50个工作场景,从案例到实践
  17. windows C/C++ 内核对象、事件对象、信号量
  18. [Java]简单易懂的并发教程
  19. 计算机网络基础以及进程查看管理
  20. Node版本的升级/降级

热门文章

  1. 纯HTML+CSS实战之制作相框效果
  2. 司法考试的心得与经验
  3. Win8系统,Wifi连接受限
  4. 贴图不说话:2500元的羊绒长丝巾
  5. linux ubuntu 关闭防火墙命令,LINUX关闭防火墙的方法
  6. 黄石理工学院计算机c语言3 2考试,黄石理工学院《C语言程序设计》试卷2及答案.doc...
  7. 排序模型进阶-FMFTRL
  8. bat代码重置电脑密码
  9. mooc计算机应用基础2020,智慧职教MOOC_计算机应用基础_2020答案
  10. 20个免费的PowerPoint模板来丰富您的演示文稿