一、组合模式基本介绍:

  • ①:组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示“整体-部分”的层次关系。
  • ②:组合模式依据树形结构来组合对象,用来表示部分、整体的层次。
  • ③:这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
  • ④:这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
  • ⑤:组合模式使得用户对单个对象和组合对象的访问具有一致性。及:组合能让客户以一致的方式处理个别对象以及组合对象。

二、组合模式解决的问题:

组合模式解决这样的问题,当我们要处理的对象可以生成一颗树形结构,而我们要对树上的节点和叶子节点进行操作时。它能够提供一致的方式,而不用考虑它是节点还是叶子节点。

  • ①:你想表示对象的部分-整体层次结构(树形结构)。
  • ②:您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
  • ③:部分、整体场景。如树形菜单,文件、文件夹、公司、部门等的管理。


三、组合模式结构图

组件(Component)类是组合类(Composite)叶子类(Leaf)的父类,可以把组合类看成是树的中间节点。
组合对象拥有一个或者多个组件对象,因此组合对象的操作可以委托给组件对象去处理,而组件对象可以是另一个组合对象或者叶子对象。
组合模式 - 图1

四、具体案例:

image.png

Company公司类,抽象类 或 接口

  1. public abstract class Company {
  2. public String name;
  3. public Company(String name) {
  4. this.name = name;
  5. }
  6. /*牺牲透明性换取单一职责原则,这样就不用考虑是叶子节点还是组合节点*/
  7. public void add(Company company) {
  8. throw new UnsupportedOperationException();
  9. }
  10. /*牺牲透明性换取单一职责原则,这样就不用考虑是叶子节点还是组合节点*/
  11. public void remove(Company company) {
  12. throw new UnsupportedOperationException();
  13. }
  14. /**
  15. * 职责范围
  16. */
  17. public void lineOfDuty() {
  18. lineOfDuty(0);
  19. }
  20. public abstract void lineOfDuty(int depth);
  21. }

ConcreteCompany具体公司类,实现Company接口,是非叶子节点。

  1. public class ConcreteCompany extends Company {
  2. private List<Company> childList = new LinkedList<>();
  3. public ConcreteCompany(String name) {
  4. super(name);
  5. }
  6. @Override
  7. public void add(Company company) {
  8. childList.add(company);
  9. }
  10. @Override
  11. public void remove(Company company) {
  12. childList.remove(company);
  13. }
  14. @Override
  15. public void lineOfDuty(int depth) {
  16. for (int i = 0; i < depth; i++) {
  17. System.out.print("----");
  18. }
  19. System.out.println("Composite: " + name);
  20. for (Company child : childList) {
  21. child.lineOfDuty(depth + 1);
  22. }
  23. }
  24. }

HRDepartment人力资源部门类,实现Company接口,是叶子节点。

  1. public class HRDepartment extends Company {
  2. public HRDepartment(String name) {
  3. super(name);
  4. }
  5. @Override
  6. public void lineOfDuty(int depth) {
  7. for (int i = 0; i < depth; i++) {
  8. System.out.print("----");
  9. }
  10. System.out.println("left: " + name);
  11. }
  12. }

FinanceDepartment财务部门类,实现Company接口,是叶子节点。

问题:为什么叶子节点有 HRDepartment人力资源部门、FinanceDepartment财务部门 两个具体类。 理由:因为 HRDepartment人力资源部门、FinanceDepartment财务部门 真实的业务中,各自执行的业务不同。举一反三

  1. public class FinanceDepartment extends Company {
  2. public FinanceDepartment(String name) {
  3. super(name);
  4. }
  5. @Override
  6. public void lineOfDuty(int depth) {
  7. for (int i = 0; i < depth; i++) {
  8. System.out.print("----");
  9. }
  10. System.out.println("left: " + name);
  11. }
  12. }

客户端调用

  1. public class Client {
  2. public static void main(String[] args) {
  3. Company root = new ConcreteCompany("北京公司总部");
  4. root.add(new HRDepartment("人力资源部"));
  5. root.add(new FinanceDepartment("财务部"));
  6. Company root_sub_HuaDong = new ConcreteCompany("上海华东分公司");
  7. root.add(root_sub_HuaDong);
  8. root_sub_HuaDong.add(new HRDepartment("人力资源部"));
  9. root_sub_HuaDong.add(new FinanceDepartment("财务部"));
  10. Company root_sub_HuaDong_NanJing = new ConcreteCompany("南京办事处");
  11. root_sub_HuaDong.add(root_sub_HuaDong_NanJing);
  12. root_sub_HuaDong_NanJing.add(new HRDepartment("人力资源部"));
  13. root_sub_HuaDong_NanJing.add(new FinanceDepartment("财务部"));
  14. Company root_sub_HuaDong_HangZhou = new ConcreteCompany("杭州办事处");
  15. root_sub_HuaDong.add(root_sub_HuaDong_HangZhou);
  16. root_sub_HuaDong_HangZhou.add(new HRDepartment("人力资源部"));
  17. root_sub_HuaDong_HangZhou.add(new FinanceDepartment("财务部"));
  18. root.lineOfDuty();
  19. }
  20. }

输出内容:

  1. Composite: 北京公司总部
  2. ----left: 人力资源部
  3. ----left: 财务部
  4. ----Composite: 上海华东分公司
  5. --------left: 人力资源部
  6. --------left: 财务部
  7. --------Composite: 南京办事处
  8. ------------left: 人力资源部
  9. ------------left: 财务部
  10. --------Composite: 杭州办事处
  11. ------------left: 人力资源部
  12. ------------left: 财务部