吴志勇的博客 吴志勇的博客
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

吴志勇

......
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Swing专题

  • java基础

  • javaweb

  • 框架

  • Maven
  • 单元测试
  • 动态代理
  • 数据库

  • netty

  • 设计模式

    • simple_factory
    • factory_method
    • abstract_factory
    • singleton
    • builder
    • prototype
    • adapter
    • decorator
    • facade
    • bridge
    • proxy
    • composite
      • 模式引入
        • 问题描述
        • 模式定义
        • 问题分析
      • 模式实现
        • 解决方案
        • 代码实现
        • 结构组成
      • 模式评价
        • 适用场景
        • 实际应用
        • 优点缺点
    • flyweight
    • observer
    • command
    • state
    • chain_of_responsibility
    • template_method
    • strategy
    • interpreter
    • mediator
    • visitor
    • memento
    • iterator
  • 微服务及架构

  • 云原生

  • Velocity模板引擎
  • 后端
  • 设计模式
wuzhiyong
2025-01-13

composite

# 组合模式

# 模式引入

# 问题描述

假设我们要给一家公司做一个 OA 系统,公司总部在北京,全国几个大城市都有子公司,其他一些省会城市是办事处,有些城市还设置了大区。总部有职能部门,各个子公司也有自己的职能部门。这是一个明显的树状结构,最简单的想法是针对不同类型(如公司或部门)组织创建不同的对象,组织之间的交互在其内部实现。但是这样有不少问题,比如无法体现公司的组织结构,交互的实现复杂混乱,新增类型时工作量巨大等等。而且对用户来说,这不同类型其实是类似的——都是组织。

# 模式定义

像刚刚这种具有层级结构,且组成对象具有一致性的情况,就适合使用组合模式。

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

# 问题分析

使用组合模式解决上面的问题,总部是根节点,下面有各个职能部门以及与其平行的子公司,每个子公司下面又有自己的职能部门。

# 模式实现

# 解决方案

  • 首先需要一个抽象类:Company,可以是一个公司或部门。包括 add、remove、display 等方法。
  • 然后分别实现树枝节点具体公司类:ConcreteCompany 和树叶节点:HrDepartment 和 FinanceDepartment,并重写抽象方法。

# 代码实现

Component 类:

public abstract class Company {
    protected String name;

    public Company(String name) {
        this.name = name;
    }

    public abstract void add(Company c);
    public abstract void remove(Company c);
    public abstract void display(int depth);
    public abstract void lineOfDuty();
}
1
2
3
4
5
6
7
8
9
10
11
12

Composite 类:

public class ConcreteCompany extends Company {

    private List<Company> children = new ArrayList<>();

    public ConcreteCompany(String name) {
        super(name);
    }

    @Override
    public void add(Company c) {
        children.add(c);
    }

    @Override
    public void remove(Company c) {
        children.remove(c);
    }

    @Override
    public void display(int depth) {
        for(int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(this.name);

        for(Company component : children) {
            component.display(depth + 2);
        }
    }

    @Override
    public void lineOfDuty() {
        for(Company component : children) {
            component.lineOfDuty();
        }
    }
}
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

Leaf 类:

public class HRDepartment extends Company {

    public HRDepartment(String name) {
        super(name);
    }

    @Override
    public void add(Company c) {}

    @Override
    public void remove(Company c) {}

    @Override
    public void display(int depth) {
        for(int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(this.name);
    }

    @Override
    public void lineOfDuty() {
        System.out.println(this.name + " 员工招聘培训管理");
    }
}

public class FinanceDepartment extends Company {
    public FinanceDepartment(String name) {
        super(name);
    }

    @Override
    public void add(Company c) {}

    @Override
    public void remove(Company c) {}

    @Override
    public void display(int depth) {
        for(int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(this.name);
    }

    @Override
    public void lineOfDuty() {
        System.out.println(this.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
39
40
41
42
43
44
45
46
47
48
49
50

Main 方法:

public class Main {
    public static void main(String[] args) {
        ConcreteCompany root = new ConcreteCompany("北京总公司");
        root.add(new HRDepartment("总公司人力资源部"));
        root.add(new FinanceDepartment("总公司财务部"));

        ConcreteCompany comp = new ConcreteCompany("上海华东分公司");
        comp.add(new HRDepartment("华东分公司人力资源部"));
        comp.add(new FinanceDepartment("华东分公司财务部"));
        root.add(comp);

        ConcreteCompany comp1 = new ConcreteCompany("南京办事处");
        comp1.add(new HRDepartment("南京办事处人力资源部"));
        comp1.add(new FinanceDepartment("南京办事处财务部"));
        root.add(comp1);

        ConcreteCompany comp2 = new ConcreteCompany("杭州办事处");
        comp2.add(new HRDepartment("杭州办事处人力资源部"));
        comp2.add(new FinanceDepartment("杭州办事处财务部"));
        root.add(comp2);

        System.out.println("\n结构图:");
        root.display(1);

        System.out.println("\n职责:");
        root.lineOfDuty();
  }
}
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

执行结果:

结构图:
-北京总公司
---总公司人力资源部
---总公司财务部
---上海华东分公司
-----华东分公司人力资源部
-----华东分公司财务部
---南京办事处
-----南京办事处人力资源部
-----南京办事处财务部
---杭州办事处
-----杭州办事处人力资源部
-----杭州办事处财务部

职责:
总公司人力资源部 员工招聘培训管理
总公司财务部 公司财务收支管理
华东分公司人力资源部 员工招聘培训管理
华东分公司财务部 公司财务收支管理
南京办事处人力资源部 员工招聘培训管理
南京办事处财务部 公司财务收支管理
杭州办事处人力资源部 员工招聘培训管理
杭州办事处财务部 公司财务收支管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 结构组成

  • Component(对象接口):主要实现所有类共有接口的默认行为,声明一个接口,用于访问和管理 Component 的子部件。
  • Composite(枝节点):定义枝节点行为,用于存储子部件,在 Component 接口中实现与子部件有关的操作,比如增加(Add)和删除(Remove)。
  • Leaf(叶节点):表示叶节点对象,叶节点没有子节点。

# 模式评价

# 适用场景

  • 体现部分与整体层次的结构时。比如例子中具有层级结构的组织结构。
  • 希望用户忽略组合对象与单个对象的不同,统一使用组合结构中的所有对象时。

# 实际应用

  • 公司管理系统。如例子所示。
  • 文件系统。文件系统是一个典型的树状层级结构。
  • 编译器。编译器会将代码最终解析为一棵语法树。

# 优点缺点

组合模式优点包括:

  • 让用户可以一致地使用组合结构和对象。比如例子中的子公司和部门。
  • 组合对象可以自由增删组件,灵活组合不同对象。

组合模式缺点包括:

  • 层级太深时结构会变得庞杂。
上次更新: 2025-02-06 00:56:14

← proxy flyweight→

Copyright © 2020-2026 wuzhiyong
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式