组合模式(合成模式 COMPOSITE)

意图

将对象组合成树形结构以表示“部分-整体”的层次结构。
Composite使得用户对单个对象和组合对象的使用具有一致性。
 

树形结构介绍

为了便于理解,我们先介绍一下树形结构
什么是树形结构?
windows系统的文件夹树形结构,部门组织架构,行政区...都是一种树形结构
对于最终的节点,称之为叶子;否则是树枝
 
对于树形结构经常会有一种使用场景:对他们下发一致性的指令
比如:对于操作系统有删除操作,即可以删除一个文件,也可以删除一个文件夹,包括他下面所有的文件
类似删除操作这种命令,并不关心这到底是一个文件(叶子)还是一个文件夹(树枝),关心在意的只是要删除目标
但是对于不同的类型,文件(叶子)还是 文件夹(树枝),他们的处理又的确是不同的
文件只需要删除就可以了,文件夹还需要递归遍历内部的文件夹,直至所有的叶子节点,并且将他们全部删除
这就出现了一个矛盾
客户端其实并不关心到底是叶子还是树枝
但是他却不得不“关心”,因为他需要分情况处理
 
客户端当然希望不关注目标的具体类型也就是希望能够满足依赖倒置原则,不关注具体类型,面向抽象进行编程
最简单的方法就是将叶子和树枝抽象出来一种新的类型组件
如此一来,删除操作仅仅关心组件类型,不在关注到底是叶子还是树枝
组件提供统一的协议约定,叶子和树枝共同实现,将它们的不同点的细节封装到他们内部的方法中
这就能够让用户“单个对象和组合对象的使用具有一致性”。 
所以,组合模式就是对于树形结构场景下的一种使用模式
 
共同的抽象提取为新的组件Component,可以表示叶子或者树枝
但是需要注意到:树枝可以有多个树叶组成,树枝上面也可能是树枝,也就是说,作为树枝的节点,也会包含Component
所以完整的结构图为:
 
所以组合模式的意图,从结构图中的Component中就可以看出来
他们都是Component,所以具有一致性。
借助于Composite与Component的关系,又能够表述整体与部分的关系。

结构

 
 
Component 抽象构建角色
根据单个对象和组合对象的特点,规定的一个抽象角色(接口或抽象类),定义了共同的行为
或者说将"整体"和"部分"提取共性,进行抽象提取。
Leaf 叶子角色
参与组合对象的单个对象,也就是定义了参加组合对象的原始根本对象的行为
叶子节点下没有下级对象
Composite组合对象角色
也就是树枝角色,单个对象组合起来的一个对象,由多个单一对象构成
并且给出组合对象的行为(实现Component约定的行为)
Client客户端角色
给单个对象或者组合对象施加命令,也就是调用Component中的方法,比如删除行为

示例代码

以删除文件为例
FileSystem文件系统类 拥有删除方法delete() 
他有两个实现类文件 File 和文件夹Folder
Folder中可以有文件和文件夹,使用内部的List<FileSystem>保存  
File的delete方法直接删除,Folder则会便利内部的List<FileSystem>  逐个删除
package composite;
public interface FileSystem {
void delete();
}
package composite;
public class File implements FileSystem {
@Override
public void delete() {
System.out.println("delete file...");
}
}
package composite;
import java.util.ArrayList;
import java.util.List; public class Folder implements FileSystem {
List<FileSystem> fileSystemList = new ArrayList<>();
@Override
public void delete() {
for(FileSystem fileSystem:fileSystemList){
fileSystem.delete();
}
}
public void add(FileSystem fileSystem){
fileSystemList.add(fileSystem);
}
}
 
客户端
package composite;
public class Client {
public static void del(FileSystem fileSystem){
fileSystem.delete();
System.out.println("DELETED");
System.out.println();
} public static void main(String[] args){
Folder folder = new Folder(); Folder folder1 = new Folder();
Folder folder2 = new Folder();
Folder folder3 = new Folder(); File file1 = new File();
File file2 = new File();
File file3 = new File();
File file4 = new File(); folder.add(file1);
folder.add(folder1);
folder.add(folder2); folder1.add(file2);
folder1.add(folder3);
folder3.add(file4); folder2.add(file3); del(folder);
del(folder1);
del(file2);
del(folder2);
}
}

 

客户端Client中    del(FileSystem fileSystem) 方法用于对整个组件进行命令下达
内部调用组件FileSystem的delete方法
通过文件夹Folder的add方法我们构建了下面这种形式的树形结构
通过下面代码进行测试

del(folder);

del(folder1);

del(file2);

del(folder2);

 
在示例代码中,借助于FileSystem这一抽象的组件Componet
将File 这一Leaf角色和 Folder 这一Composite角色  组织成 “部分--整体”的树形结构
并且,对于客户端提供统一的外在形式----Component
使得客户端对单个对象和组合对象的使用具有一致性
这就是组合模式的运用
 

两种形式

如果你有留意,可以看得到前面的代码示例中
FileSystem中仅仅只有一个delete方法
File也实现了这一个方法,但是Folder 中却有了add方法
也就是说,Composite角色中有与Component中不同的方法!
 
树枝中可以有树枝或者叶子节点,也就是组合对象中可以包含组合对象或者单一对象
那么,也就是说:组合对象要提供子对象的管理方法,比如上面的add  可能还会有remove等
上面的例子中,我们将add方法安置于Composite 中
这被称为安全方式的合成模式
因为是在Composite中管理子对象,叶子节点类型的对象根本就没有这些方法,所以也不能对客户端执行这些方法
但是,叶子节点和树枝节点不够透明,他们拥有不同的方法
 
另外一种是将子对象的管理全部托管在Component中
也就是叶子节点和树枝节点都将拥有这些方法,方法都是一样的,对客户端来说,叶子和树枝在方法接口层面上的区别没有了
客户端可以完全同等的对待它们两者,这就是透明方式的合成模式
但是,它不够安全,因为叶子节点和树枝节点逻辑上本来就是不相同的
叶子节点也不会有下一级子节点,所以这些方法没有意义,而且如果使用编译期间也不会报错,会把问题留到运行中
 
两种方式中,透明就不够安全,安全就不透明,所以根据实际情况按照需求进行选择

总结

组合模式的根本在于抽象组件,对于具有整体与部分关系的事物,如果需要一致性的外在表现,就可以提取共性进行抽象,这就是组合模式。
将相关联的对象组织成“部分--整体”的树形结构形式,通过抽象构建,所有的节点都是Component
对于客户端来说,不管到底是Leaf还是Composite,他们都是Component
高层模块并不需要关心,处理的到底是单个对象还是组合的对象
只要是比较符合“部分--整体”关系,或者说是树形结构,以及当你希望用户可以忽略组合对象和单个对象的区别时,那么就可以考虑使用组合模式 
当增加新类型组件时,新定义的Composite或者Leaf子类自动的与已有的结构和客户代码一起工作
客户端程序不需要因此而变化,从这个角度看,符合开闭原则。

组合模式 合成模式 COMPOSITE 结构型 设计模式(十一)的更多相关文章

  1. OOAD-设计模式(四)结构型模式之适配器、装饰器、代理模式

    前言 前面我们学习了创建型设计模式,其中有5中,个人感觉比较重要的是工厂方法模式.单例模式.原型模式.接下来我将分享的是结构型模式! 一.适配器模式 1.1.适配器模式概述 适配器模式(Adapter ...

  2. 享元模式 FlyWeight 结构型 设计模式(十五)

    享元模式(FlyWeight)  “享”取“共享”之意,“元”取“单元”之意. 意图 运用共享技术,有效的支持大量细粒度的对象. 意图解析 面向对象的程序设计中,一切皆是对象,这也就意味着系统的运行将 ...

  3. 代理模式 PROXY Surrogate 结构型 设计模式(十四)

    代理模式 PROXY 别名Surrogate 意图 为其他的对象提供一种代理以控制对这个对象的访问. 代理模式含义比较清晰,就是中间人,中介公司,经纪人... 在计算机程序中,代理就表示一个客户端不想 ...

  4. 桥接模式 桥梁模式 bridge 结构型 设计模式(十二)

      桥接模式Bridge   Bridge 意为桥梁,桥接模式的作用就像桥梁一样,用于把两件事物连接起来   意图 将抽象部分与他的实现部分进行分离,使得他们都可以独立的发展.  意图解析 依赖倒置原 ...

  5. 11、Composite 组合模式 容器与内容的一致性(抽象化) 结构型设计模式

    1.Composite模式定义 组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及整体层次.这 ...

  6. 合成模式(Composite)-结构型

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

  7. 享元模式/Flyweight模式/对象结构型/设计模式

    flyweight 享元模式(对象结构型) Flyweight在拳击比赛中指最轻量级,即"蝇量级"或"雨量级",这里选择使用"享元模式"的意 ...

  8. 12、Decorator 装饰器 模式 装饰起来美美哒 结构型设计模式

    1.Decorator模式 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式(Decorator Pattern)允许向一个现 ...

  9. 设计模式学习之装饰者模式(Decorator,结构型模式)(16)

    参考地址:http://www.cnblogs.com/zhili/p/DecoratorPattern.html 一.定义:装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相 ...

随机推荐

  1. MYSQL必知必会学习笔记

    8.1.1 百分号( %)通配符最常使用的通配符是百分号( %).在搜索串中, %表示任何字符出现任意次数.例如,为了找出所有以词jet起头的产品,可使用以下SELECT语句:SELECT prod_ ...

  2. Egret的容器--删除对象,遮罩

    class P91F extends egret.Sprite { public constructor() { super(); this.addEventListener(egret.Event. ...

  3. IaaS,PaaS和SaaS

    云计算的三种服务模式:IaaS,PaaS和SaaS IaaS: Infrastructure-as-a-Service(基础设施即服务)是第一层. PaaS: Platform-as-a-Servic ...

  4. 多路分支----switch语句

    switch-case与if-else有相似的作用,都是表达分支的方式. 语法形式: switch(type){ case 常量1: do something; break; case 常量2: do ...

  5. django 源码报错

    启动django ,一直提示一个 AttributeError: 'str' object has no attribute 'decode' 哥,查了一下午google,就怕是自己判断错了,最后在一 ...

  6. Springboot中关于跨域问题的一种解决方法

    前后端分离开发中,跨域问题是很常见的一种问题.本文主要是解决 springboot 项目跨域访问的一种方法,其他 javaweb 项目也可参考. 1.首先要了解什么是跨域 由于前后端分离开发中前端页面 ...

  7. 对象池----unity中应用

    对象池应用在unity中能减少资源消耗,节省内存空间具体原理不再赘述. 以下是他的操作步骤:(注意:对象池中应用到了栈或对队列!) 1).先建立一个(怪物)物体   mMonster; 2).再建立一 ...

  8. 【DFS】素数环问题

    题目: 输入正整数n,对1-n进行排列,使得相邻两个数之和均为素数,输出时从整数1开始,逆时针排列.同一个环应恰好输出一次.n<=16 如输入: 6 输出: 1 4 3 2 5 6 1 6 5 ...

  9. Android端IM应用中的@人功能实现:仿微博、QQ、微信,零入侵、高可扩展

    本文由“猫爸iYao”原创分享,感谢作者. 1.引言 最近有个需求:评论@人(没错,就是IM聊天或者微博APP里的@人功能),就像下图这样:   ▲ 微信群聊界面里的@人功能    ▲ QQ群聊界面里 ...

  10. [Swift]LeetCode236. 二叉树的最近公共祖先 | Lowest Common Ancestor of a Binary Tree

    Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...