组合模式(合成模式 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. 按月分表(create table)

    PHP 按月分表控制台命令(yii2版) <?php /** * @Purpose: 按月分表脚本 * @User: Chrdai * @Date: 2019/3/19 * @Time: 15: ...

  2. python中的矩阵、多维数组

    2. 创建一般的多维数组 import numpy as np a = np.array([1,2,3], dtype=int)  # 创建1*3维数组   array([1,2,3]) type(a ...

  3. 一步一步 copy163: 网易严选 ---- vue-cli

    面试点 组件间通信 生命周期函数 路由 - 参数 - 重定向 vuex 参考 网易严选商城小程序全栈开发,域名备案中近期上线(mpvue+koa2+mysql) 小程序服务端源码地址 小程序源码地址 ...

  4. js 单行注释

    不可以: var a = 1;//这是注释 应当: var a = 1; //这是注释 1

  5. Flutter 读写本地文件

    文档 注意 安装 path_provider 插件后重启f5, 而不是等待热更新 demo import 'dart:io'; import 'dart:async'; import 'package ...

  6. Maven插件一览

    maven-assembly-plugin 将对应模块依赖在  mvn package 阶段全部打到一个 jar 包里面: java -cp xx.jar package.name.MainClass ...

  7. 学用HBuilder开发App的看过来

    自己的呕心沥血之作吧,花了一年时间,系统介绍HTML5 App开发的相关技术. 越来越多的公司采用HTML5来快速开发移动跨平台App,它支持当前市场流行的移动设备. 本书主要介绍了HTML5在移动A ...

  8. truffle unbox react 出坑指南

    最近几天差点就被这鬼东西给逼疯了,truffle init .truffle unbox webpack 不管我怎么运行都是对的,唯独truffle unbox react 不管在哪个windows都 ...

  9. Lesson 25 Do the English speak English?

    Text I arrived London at last. The railway station was big, black and dark. I did not know the way t ...

  10. Java并发编程基础之volatile

    首先简单介绍一下volatile的应用,volatile作为Java多线程中轻量级的同步措施,保证了多线程环境中“共享变量”的可见性.这里的可见性简单而言可以理解为当一个线程修改了一个共享变量的时候, ...