组合模式
# 一、概述
组合(Composite)模式,将对象组合成树状结构,并且能像使用独立对象一样使用它们。
组合模式的核心是被管理对象能够用树形结构来表示。
# 1.1 解决了什么问题

对于上图表示的这样一个树形结构,实际上是有是三个层级关系,如果要通过传统的方式对其进行管理,那么必须要定义三个类。对于每个类都要实现对应的增删改查操作。如果层级变得更深一点,专业下面加了班级,班级下班加了小组,意味着还要再增加新的类,而且对于每个新增的类都需要去实现对应的管理方法。
# 1.2 解决方案
对于树形结构而言,如果按照传统的方式每一层都定义为一个类的话是不现实的。在组合模式的思想里无需关系树形结构中的每一层具体是什么对象,而是将其看做成一个组合,对于任意一层的操作都以相同的方式进行处理,即无论操作哪一层,暴露给客户端的接口都是相同的。
# 二、实现方式
# 2.1 角色
- Component:用来描述树结构中所有对象的共有的接口。
- Leaf:树结构中的叶子结点。
- Composite:非叶子结点,无需关心自己的子结点,只需通过 Component 中的接口和子结点进行交互。
- Client:通过 Component 接口与所有结点进行交互。
# 2.2 代码
在 Component 中定义组合的共用操作接口:
public abstract class OrgComponent {
    // 结点名称
    public String name;
    // 当前结点人数
    public int userCount;
    public List<OrgComponent> subOrgs = new ArrayList<>();
    public OrgComponent(String name) {
        this.name = name;
    }
    public OrgComponent(String name, int userCount) {
        this.name = name;
        this.userCount = userCount;
    }
    /**
     * 添加子结点
     *
     * @param org
     * @throws Exception
     */
    public abstract void addSubOrg(OrgComponent org) throws Exception;
    /**
     * 获取子结点个数
     *
     * @return
     */
    public abstract int getSubOrgCount();
    /**
     * 获取所有子结点人数
     *
     * @return
     */
    public abstract int getSubOrgUserCount();
    /**
     * 获取所有子结点以及当前节点人数
     *
     * @return
     */
    public abstract int getUserCount();
}
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
39
40
41
42
43
44
45
46
47
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
39
40
41
42
43
44
45
46
47
定义组合类,实现 Component 的所有抽象方法:
public class OrgComposite extends OrgComponent {
    public OrgComposite(String name) {
        super(name);
    }
    public OrgComposite(String name, int userCount) {
        super(name, userCount);
    }
    @Override
    public void addSubOrg(OrgComponent org) {
        subOrgs.add(org);
    }
    @Override
    public int getSubOrgCount() {
        int count = 0;
        for (OrgComponent subOrg : subOrgs) {
            count += subOrg.subOrgs.size() + 1;
        }
        return count;
    }
    @Override
    public int getSubOrgUserCount() {
        int count = 0;
        for (OrgComponent subOrg : subOrgs) {
            if (subOrg instanceof OrgLeaf) {
                count += subOrg.getUserCount();
            } else {
                count += subOrg.getSubOrgUserCount();
            }
        }
        return count;
    }
    @Override
    public int getUserCount() {
        return userCount + getSubOrgUserCount();
    }
}
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
39
40
41
42
43
44
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
39
40
41
42
43
44
定义叶子结点,同样实现 Component 中的抽象方法,但是由于叶子结点没有子结点,所以对于个别方法的处理方式和组合类不同:
public class OrgLeaf extends OrgComponent {
    public OrgLeaf(String name, int userCount) {
        super(name, userCount);
    }
    @Override
    public void addSubOrg(OrgComponent org) throws Exception {
        throw new Exception("叶子结点,无法停添加子结点");
    }
    @Override
    public int getSubOrgCount() {
        return subOrgs.size();
    }
    @Override
    public int getSubOrgUserCount() {
        return 0;
    }
    @Override
    public int getUserCount() {
        return userCount;
    }
}
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
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
客户端
public class CompositeTest {
    public static void main(String[] args) throws Exception {
        // 每个学校结点和学院结点都有两个领导
        OrgComponent root = new OrgComposite("XX大学", 2);
        OrgComponent school1 = new OrgComposite("计算机学院", 2);
        OrgComponent school2 = new OrgComposite("理学院", 2);
        OrgComponent school3 = new OrgComposite("外国语学院", 2);
        OrgComponent major1 = new OrgLeaf("专业1", 50);
        OrgComponent major2 = new OrgLeaf("专业2", 30);
        OrgComponent major3 = new OrgLeaf("专业3", 10);
        OrgComponent major4 = new OrgLeaf("专业4", 20);
        OrgComponent major5 = new OrgLeaf("专业5", 30);
        OrgComponent major6 = new OrgLeaf("专业6", 40);
        school1.addSubOrg(major1);
        school1.addSubOrg(major2);
        school2.addSubOrg(major3);
        school2.addSubOrg(major4);
        school3.addSubOrg(major5);
        school3.addSubOrg(major6);
        root.addSubOrg(school1);
        root.addSubOrg(school2);
        root.addSubOrg(school3);
        System.out.println("学校总结点数:" + root.getSubOrgCount());
        System.out.println("学校总人数:" + root.getUserCount());
        System.out.println("学校子结点总人数:" + root.getSubOrgUserCount());
        System.out.println("计算机学院子结点:" + school1.getSubOrgCount());
    }
}
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
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
学校总结点数:9
学校总人数:182
学校子结点总人数:180
计算机学院子结点:2
1
2
3
4
2
3
4
# 三、源码中的应用
- java.util.Map#putAll(Map)
- java.util.List#addAll(Collection)
- java.util.Set#addAll(Collection)
上次更新: 2023/11/01, 03:11:44