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

合成模式

  合成模式把部分和整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由它们复合而成的合成对象同等看待。比如,一个文件系统就是一个典型的合成模式系统。下图是常见的计算机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<Component> childComponents = new ArrayList<Component>();
//组合对象的名字
private String name;
public Composite(String name) {
this.name = name;
}
public void addChild(Component child) {
childComponents.add(child);
}
public void removeChild(int index) {
childComponents.remove(index);
}
public List<Component> getChild() {
return childComponents;
}
@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; // 叶子对象的名字
public Leaf(String name) {
this.name = name;
}
//输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字
@Override
public void printStruct(String preStr) {
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); // 输出组建自身的名称
public void addChild(Component child) {
throw new UnsupportedOperationException("对象不支持此功能");
}
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; / / 组合对象的名字
public Composite(String name) {
this.name = name;
}
public void addChild(Component child) {
childComponents.add(child);
}
public void removeChild(int index) {
childComponents.remove(index);
}
public List<Component> getChild() {
return childComponents;
}
@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; // 输出组建自身的名称
public Leaf(String name) {
this.name = name;
}
@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对象,具体的类型对于客户端而言是透明的,是无须关心的。

  对于合成模式而言,在安全性和透明性上,会更看重透明性,毕竟合成模式的目的是:让客户端不再区分操作的是树枝对象还是树叶对象,而是以一个统一的方式来操作。而且对于安全性的实现,需要区分是树枝对象还是树叶对象。有时候,需要将对象进行类型转换,却发现类型信息丢失了,只好强行转换,这种类型转换必然是不够安全的。因此在使用合成模式的时候,建议多采用透明性的实现方式。

合成(composite)模式的更多相关文章

  1. 组合模式/composite模式/对象结构型模式

    组合模式/composite模式/对象结构型 意图 将对象组合成树形结构以表示"整体--部分"的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 动机 C ...

  2. C++基础——模拟事务 (2)Composite模式

    =================================版权声明================================= 版权声明:原创文章 禁止转载  请通过右侧公告中的“联系邮 ...

  3. Composite模式

    1 意图:将对象组成树形结构,以表示“部分——整体”的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 2 动机:同意处理图元对象和包含图元的容器对象.Composite通过 ...

  4. Java 实现组合(Composite)模式

    类图 /** * 树 总体 * * @author stone * */ public class Tree { private TreeNode root; //根节点 public Tree(St ...

  5. 【结构型】Composite模式

    组合模式意在将对象组合成树形结构以表示部分与整体的层次结构关系,并且用户对单个对象的操作以有对组合对象的操作都是一致的.即:组合对象 is-a 单个对象,同时又可以组合着 n 个的单个对象(甚至于其他 ...

  6. (原创)composite模式和bridge模式是天生的好朋友

    composite模式的意图是:将对象组合成树形结构以表示“部分-整体”的层次结构.composite使得用户对单个对象和组合对象的使用具有一致性.它的类图如下: composite模式的实现分为透明 ...

  7. Java设计模式(8)组合模式(Composite模式)

    Composite定义:将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. Composite比较容易理解,想到Composite就应该想到树 ...

  8. 设计模式之——Composite模式

    composite模式又叫做组合模式/复合模式. 它是一种能够使容器与内容具有一致性,创造出递归结构的模式. 示例程序是列出文件夹以及其内部文件与文件夹一览的功能: 可以由示例图看出,有一个电影文件夹 ...

  9. Composite模式 组合模式

    Android的ViewGroup 和 View 的关系,即是采用组合模式 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件 ...

随机推荐

  1. Spring初识(通过小实例清晰认识Spring)

    1.spring架构: spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,iba ...

  2. 学点Groovy来理解build.gradle代码

    在写这篇博客时,搜索参考了很多资料,网上对于 Groovy 介绍的博客已经特别多了,所以也就没准备再详细的去介绍 Groovy,本来也就计划写一些自己认为较重要的点.后来发现了 Groovy 的官方文 ...

  3. POJ1275出纳员的雇佣【差分约束】

    出纳员的雇佣 Tehran的一家每天24小时营业的超市,需要一批出纳员来满足它的需要.超市经理雇佣你来帮他解决问题:超市在每天的不同时段需要不同数目的出纳员(例如:午夜时只需一小批,而下午则需要很多) ...

  4. 手机自动化测试:appium源码分析之bootstrap十一

    手机自动化测试:appium源码分析之bootstrap十一   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣 ...

  5. 老李分享:Web Services 特性 1

    老李分享:Web Services 特性   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:9 ...

  6. Linux命令的复习总结学习

    1.-------------------------linux系统介绍------------------------------------------------------- Linux是一套 ...

  7. Learning to Rank简介

    Learning to Rank是采用机器学习算法,通过训练模型来解决排序问题,在Information Retrieval,Natural Language Processing,Data Mini ...

  8. 关于解决配置Tomact过程中出现的相关问题

    最近在学习JavaWeb, 但是在第一步的时候就出现问题了, 什么问题呢, 就是关于Tomact的配置. 下面我就详细说明一下我配置过程中出现的问题以及怎么解决的,  希望对大家能有所帮助. 首先,我 ...

  9. Webpack模块加载器

    一.介绍 Webpack是德国开发者 Tobias Koppers 开发的模块加载器,它能把所有的资源文件(JS.JSX.CSS.CoffeeScript.Less.Sass.Image等)都作为模块 ...

  10. [Oracle]Audit(二)--清理Audit数据

    在上一篇,初步了解了Audit的作用以及如何使用Audit,本篇记录如何手动清理Audit数据. (一) 概述 Audit的数据主要存储在sys.aud$表中,该表默认位于system表空间中,我们根 ...