组合模式

物以类聚-组合模式

定义

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

使用场景

表示对象的部分-整体层次机构时

从一个整体中能够独立出部分模块或功能的场景

简单实现

表示文件和文件夹抽象类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package CombinedMode;

import java.util.ArrayList;
import java.util.List;

public abstract class Dir {
    //声明一个list成员变量存储文件夹下的所有元素
    protected List<Dir> dirs=new ArrayList<Dir>();

    private String name;//当前文件夹或用户名
    public Dir(String name){
        this.name=name;
    }
    //添加一个文件或文件夹
    public abstract void addDir(Dir dir);
    //移除一个文件或文件夹
    public abstract void rmDir(Dir dir);
    //清空文件夹内的所有元素
    public abstract void clear();
    //输出文件夹目录结构
    public abstract void print();
    //获取文件夹内所有文件或者子文件夹
    public abstract List<Dir> getFiles();

    //获取文件或文件夹名字
    public String getName(){
        return name;
    }
}

表示文件夹的类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package CombinedMode;

import java.util.Iterator;
import java.util.List;

public class Folder extends Dir {
    public Folder(String name){
        super(name);
    }
    public void addDir(Dir dir) {
        dirs.add(dir);
    }

    public void rmDir(Dir dir) {
        dirs.remove(dir);
    }

    public void clear() {
        dirs.clear();
    }

    public void print() {
        System.out.print(getName()+"(");
        Iterator<Dir> iterator=dirs.iterator();
        while (iterator.hasNext()){
            Dir dir=iterator.next();
            dir.print();
            if(iterator.hasNext()){
                System.out.print(",");
            }
        }
        System.out.print(")");
    }

    public List<Dir> getFiles() {
        return dirs;
    }
}

表示文件的类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package CombinedMode;

import java.util.List;

public class File extends Dir {
    public File(String name){
        super(name);
    }

    public void addDir(Dir dir) {
        throw new UnsupportedOperationException("文件对象不支持该操作");
    }

    public void rmDir(Dir dir) {
        throw new UnsupportedOperationException("文件对象不支持该操作");
    }

    public void clear() {
        throw new UnsupportedOperationException("文件对象不支持该操作");
    }

    public void print() {
        System.out.print(getName());
    }

    public List<Dir> getFiles() {
        throw new UnsupportedOperationException("文件对象不支持该操作");
    }
}

测试类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package CombinedMode;

public class Client {
    public static void main(String[] args) {
        Dir diskC=new Folder("C");
        diskC.addDir(new File("image.txt"));

        Dir dirWin=new Folder("Windows");
        dirWin.addDir(new File("explorer.exe"));
        diskC.addDir(dirWin);

        Dir dirPer=new Folder("PerfLogs");
        dirPer.addDir(new File("null.txt"));
        diskC.addDir(dirPer);

        Dir dirPro=new Folder("Program file");
        dirPro.addDir(new File("ftp.txt"));
        diskC.addDir(dirPro);

        diskC.print();
    }
}

输出结果

show.png

总结

优点

  1. 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,他让高层模块忽略了层次的差异,方便对整个层次结构进行控制
  2. 高层模块可以一致的使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了高层模块的代码
  3. 在组合模式中增加了新的枝干构件和叶子构件都很方便,无需对现有类库进行任何修改,符合“开闭原则”
  4. 组合模式为树形结构的面向对象实现提供实现提供了一种灵活的解决方案,通过叶子对象和枝干对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单

缺点

  1. 在新增构件时不好对枝干中的构件类型进行限制,不能依赖类型系统来施加这些约束,因为在大多数情况下,它们都来自于相同的抽象层,此时,必须行时进行类型检查来实现,这个实现过程较为复杂