组合模式 合成模式 COMPOSITE 结构型 设计模式(十一)

组合模式(合成模式 COMPOSITE)

意图

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

树形结构介绍

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

结构

image_5bfcb125_3a4e
 
 
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);
    }
}

 

image_5bfcb125_614
 
客户端
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方法咱们构建了下面这种形式的树形结构
image_5bfcb125_7f82
经过下面代码进行测试

        del(folder); html

        del(folder1); java

        del(file2); web

        del(folder2); 编程

 

image_5bfcb125_6062
 
在示例代码中,借助于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子类自动的与已有的结构和客户代码一块儿工做
客户端程序不须要所以而变化,从这个角度看,符合开闭原则。
相关文章
相关标签/搜索