组合模式(Composite)
组合(composite)模式的定义,组合模式又叫做 “部分-整体” 模式,他是一种将对象组合成树状层次结构的模式,用来表示 “部分-整体” 的关系,使用户对单个对象和组合对象具有一致的访问性,组合模式属于结构型模式
组合模式的结构与特点
1.比如公司的组织架构就是一颗树,总部下来会有财务,行政,人力,研发,市场等部门,每个部门下有会有不同的子部门
2.在比如文件结构,整体文件结构是一个树形结构,目录和文件,一个目录下面又会有子目录或者文件
组合模式的使用场景
1.希望客户端可以忽略组合对象和单个对象的差异是
2.对象层次具备整体和部分,呈属性结构(如树形菜单,操作系统目录结构,公司组织架构等)
组合模式的主要角色
1.抽象构建(Component)角色,主要作用是为树叶和树枝构建声明公共接口,在透明的组合模式中抽象构建还声明和管理子类的接口,在安全模式中组合模式不声明和管理子类的接口,管理工作由树枝构建完成
2.树叶构建(Leaf)角色,是组合模式中的叶子节点对象,它没有子节点,用于实现抽象构建角色中声明的公共接口
3.树枝构建(Composite)角色,是组合模式中的分支节点对象,它有子节点,它实现了抽象构建角色中声明的公共接口,主要作用是存储和管理子部件,通常包含 Add(),Remove(),GetChild()等方法
组合模式都优缺点
优点
1.组合模式使得客户端可以一致的访问单个对象或者组合对象,无需关心处理的对象是单个对象,还是组合对象,这简化了客户端的代码
2.更容易在组合体中加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足开闭原则
缺点
1.设计复杂,客户端要花更多的时间去理清类之间的层次关系
组合模式的实现
透明组合模式
创建抽象构建
/**
* 抽象构建 Component 透明组合模式
* 提供树枝和树叶构建公共的接口,并实现它们的默认行为
* 透明式组合模式还声明访问和管理子类的接口
* 安全式组合模式将访问和管理子类的接口由树枝构建完成
*/
public abstract class Component {
// 树枝和树叶的公共接口
public abstract void opertation();
// 声明管理子类的接口
public boolean add(Component component){
throw new UnsupportedOperationException("不支持添加操作");
}
public boolean remove(Component component){
throw new UnsupportedOperationException("不支持删除操作");
}
public Component getChild(int index){
throw new UnsupportedOperationException("不支持获取操作");
}
}
创建树枝构建
/**
* 树枝构建 Componsite
* 是组合模式中的分支构建,它有子节点,实现类抽象构建中公共的接口
* 主要作用是管理子部件,通常包含 add(),remove,getChild()方法等...
*/
public class Composite extends Component{
// 保存子节点
private List<Component> components = new ArrayList<Component>();
private String name;
private int level;
public Composite(String name,int level){
this.name = name;
this.level = level;
}
@Override
public boolean add(Component component) {
return components.add(component);
}
@Override
public boolean remove(Component component) {
return components.remove(component);
}
@Override
public Component getChild(int index) {
return components.get(index);
}
@Override
public void opertation() {
System.out.println(this.name);
for(Component c : this.components){
for(int i=0;i<level;i++){
System.out.print(" ");
}
c.opertation();
}
}
}
创建树叶构建
/**
* 树叶构建 Leaf 是组合模式中的叶子节点,没有子节点,实现抽象构建中声明的公共接口
*/
public class Leaf extends Component{
private String name;
public Leaf(String name){
this.name = name;
}
@Override
public void opertation() {
System.out.println(this.name);
}
}
测试
public static void main(String[] args) {
Component root = new Composite("XXX责任有限公司",1);
Component leaf = new Leaf("董事长");
Component c1 = new Composite("财务部", 2);
Component c2 = new Composite("人事部", 2);
Component c3 = new Composite("技术部",2);
root.add(leaf);
root.add(c1);
root.add(c2);
root.add(c3);
Component leaf1 = new Leaf("财务部主管");
Component leaf2 = new Leaf("人事部主管");
Component leaf3 = new Leaf("技术部主管");
c1.add(leaf1);
c2.add(leaf2);
c3.add(leaf3);
Component c4 = new Composite("技术部员工", 3);
Component emp1 = new Leaf("技术1");
Component emp2 = new Leaf("技术2");
Component emp3 = new Leaf("技术3");
c3.add(c4);
c4.add(emp1);
c4.add(emp2);
c4.add(emp3);
root.opertation();
}
结果
XXX责任有限公司
董事长
财务部
财务部主管
人事部
人事部主管
技术部
技术部主管
技术部员工
技术1
技术2
技术3
透明组合模式是把组合使用的方法放到抽象类中,不管叶子对象和树枝对象都是相同的结构,这样做的好处就是叶子节点和树枝节点对于外界没有区别,他们具有完全一致的行为接口,但因为 Leaf 叶子节点类本身并不具备 add(),remove(),getChild()功能,所以实现它是没有意义的,这是就需要使用安全组合模式,它不声明管理子类的接口,声明和管理子类的接口交给子类自己去完成
安全组合模式
创建抽象构建,只声明叶子节点和组合节点公共接口,将管理子类的接口,交个子类自己去完成
/**
* 安全组合模式
* 抽象构建 Component 目录类
* 只声明叶子节点和设置节点公共的接口
*/
public abstract class Directory {
protected String name;
// 声明子类必须实现的构造方法
public Directory(String name){
this.name = name;
}
// 获取分支下的所有树枝节点和叶子节点
public abstract void operation(int depth);
}
创建树枝节点,实现抽象构建的接口,并提供管理子类的方法
/**
* 树枝节点 Composite
* 实现抽象构建的公共接口,声明管理子类的接口
* 一般包括 add(),remove(),getChild() 等方法
*/
public class Folder extends Directory{
// 管理组合对象
private List<Directory> directories = new ArrayList<Directory>();
public Folder(String name) {
super(name);
}
public boolean add(Directory directory){
return this.directories.add(directory);
}
public boolean remove(Directory directory){
return this.directories.remove(directory);
}
public Directory getChild(int index){
return this.directories.get(index);
}
@Override
public void operation(int depth) {
// 输出出行结构
for(int i=0;i<depth;i++){
System.out.print("- ");
}
System.out.println(this.name);
// 便利下一级节点
for(Directory d : this.directories){
d.operation(depth+1);
}
}
}
创建叶子节点,实现抽象构建的方法
/**
* 叶子节点 Leaf 文件类
* 实现抽象构建声明的公共接口
*/
public class File extends Directory{
public File(String name) {
super(name);
}
@Override
public void operation(int depth) {
// 输出树形结构
for(int i=0;i<depth;i++){
System.out.print("- ");
}
System.out.println(this.name);
}
}
测试
public static void main(String[] args) {
Folder root = new Folder("D:\\盘");
Folder office = new Folder("office组件");
Directory excel = new File("excel.exe");
Directory word = new File("word.exe");
// 添加 office 组件
office.add(excel);
office.add(word);
Directory mp3 = new File("下辈子我还记得你.mp3");
Folder other = new Folder("高清无码...");
Folder ont = new Folder("【一品道】");
other.add(ont);
Directory m1 = new File("天线宝宝第一集.mp4");
Directory m2 = new File("天线宝宝第二集.mp4");
Directory m3 = new File("天线宝宝第三集.mp4");
ont.add(m1);
ont.add(m2);
ont.add(m3);
// 给根目录添加节点
root.add(office);
root.add(mp3);
root.add(other);
root.operation(1);
}
结果
- D:\盘
- - office组件
- - - excel.exe
- - - word.exe
- - 下辈子我还记得你.mp3
- - 高清无码...
- - - 【一品道】
- - - - 天线宝宝第一集.mp4
- - - - 天线宝宝第二集.mp4
- - - - 天线宝宝第三集.mp4