Skip to content

Files

Latest commit

Feb 9, 2025
126072d · Feb 9, 2025

History

History

composite-pattern

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Apr 29, 2024
Apr 29, 2024
Apr 29, 2024
Feb 9, 2025
Apr 29, 2024
Feb 9, 2025
Apr 27, 2023

README.md

【组合设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

简介

组合模式(Composite Pattern),又叫部分整体模式,是一种结构型设计模式。用于把一组类似的对象当作一个单一的对象来看。组合模式依据树形结构来组合对象,用不同组件来构建某个部分或整体对象。

如果你需要实现树状对象结构,可以使用组合模式。如果你希望客户端代码以相同方式处理简单和复杂元素,可以使用该模式。

作用

  1. 符合开闭原则。无需更改现有代码,就可以在应用中添加新元素,使之成为对象树的一部分。
  2. 模糊了简单元素和复杂元素的概念,程序可以像处理简单元素一样来处理复杂元素,从而使得程序与复杂元素的内部结构解耦。

实现步骤

  1. 创建抽象构件(Component)接口,用于声明树叶构件和树枝构件的默认行为。
  2. 创建树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。
  3. 定义树叶构件(Leaf)角色:是组合中的叶子节点对象,它没有子节点,用于继承或实现抽象构件。

UML

Java语言代码

基础部件接口

// OrganizationComponent.java 定义部件接口或抽象类,分支和叶子节点遵循该类约定
public interface OrganizationComponent {
   public void add(OrganizationComponent component);

   public void remove(OrganizationComponent component);

   public OrganizationComponent getChild(int index);

   public void operation();

   public String getName();
}

具体部件实现

// CompanyComposite.java 实现部件的树枝构件1
public class CompanyComposite implements OrganizationComponent {

   private String name;
   private List<OrganizationComponent> children = new ArrayList<OrganizationComponent>();

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

   public void add(OrganizationComponent component) {
      children.add(component);
   }

   public void remove(OrganizationComponent component) {
      children.remove(component);
   }

   public OrganizationComponent getChild(int index) {
      return children.get(index);
   }

   public void operation() {
      System.out.println(this.getClass().getName() + " CompanyComposite::operation() " + this.name);
      for (Object component : children) {
         ((OrganizationComponent) component).operation();
      }
   }

   public String getName() {
      return name;
   }
}
// DepartmentComposite.java  实现部件的树枝构件2
public class DepartmentComposite implements OrganizationComponent {

   private String name;
   private List<OrganizationComponent> children = new ArrayList<OrganizationComponent>();

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

   public void add(OrganizationComponent component) {
      children.add(component);
   }

   public void remove(OrganizationComponent component) {
      children.remove(component);
   }

   public OrganizationComponent getChild(int index) {
      return children.get(index);
   }

   public void operation() {
      System.out.println(this.getClass().getName() + " DepartmentComposite::operation() " + this.name);
      for (Object component : children) {
         ((OrganizationComponent) component).operation();
      }
   }

   public String getName() {
      return name;
   }
}
// EmployeeLeaf.java 实现部件的叶子节点,叶子节点不能再含有子节点
public class EmployeeLeaf implements OrganizationComponent {

   private String name;

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

   // 叶子节点不能再增加内容
   public void add(OrganizationComponent component) {
      System.out.println("Leaf can't add.");
   }

   // 叶子节点没有移除内容
   public void remove(OrganizationComponent component) {
      System.out.println("Leaf can't remove.");
   }

   // 叶子节点无获取子节点
   public OrganizationComponent getChild(int index) {
      System.out.println("Leaf can't getChild.");
      return null;
   }

   public void operation() {
      System.out.println(this.getClass().getName() + " EmployeeLeaf::operation() " + this.name);
   }

   public String getName() {
      return name;
   }
}

测试调用

    /**
     * 组合模式依据树形结构来组合对象,用不同组件来构建整体对象。
     * 不同组件之间有相同的接口约束,有不同的具体实现。
     * 先定义顶级节点,然后陆续加入枝叶节点和叶子节点,这样不断添加,将零散的个体组成一个整体。
     */

    // 通过组合模型组合了一个部件,分支和节点可以随意增删
    OrganizationComponent com = new CompanyComposite("西天旅游有限公司");
    OrganizationComponent com1 = new DepartmentComposite("总裁办");
    OrganizationComponent com2 = new DepartmentComposite("行动队");
    OrganizationComponent com3 = new DepartmentComposite("后勤组");
    OrganizationComponent leaf1 = new EmployeeLeaf("唐三藏");
    OrganizationComponent leaf2 = new EmployeeLeaf("孙悟空");
    OrganizationComponent leaf3 = new EmployeeLeaf("猪悟能");
    OrganizationComponent leaf4 = new EmployeeLeaf("沙悟净");

    com.add(com1);
    com.add(com2);
    com.add(com3);

    // leaf1属于com1
    com1.add(leaf1);
    // leaf2, leaf3属于com2
    com2.add(leaf2);
    com2.add(leaf3);

    // 添加再删除
    DepartmentComposite dept1 = new DepartmentComposite("小分队");
    com2.add(dept1);
    EmployeeLeaf tmp1 = new EmployeeLeaf("临时工");
    dept1.add(tmp1);
    dept1.remove(tmp1);

    // leaf4属于com3
    com3.add(leaf4);

    // 执行全部节点动作
    com.operation();

    // 获取某个节点
    OrganizationComponent employee = (EmployeeLeaf) com.getChild(1).getChild(0);
    System.out.println(employee.getName());

C语言代码

func.h 自定义头文件

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

// 定义部件接口或抽象类,分支和叶子节点遵循该类约定
typedef struct OrganizationComponent
{
    char name[200];
    void (*add)(struct OrganizationComponent *, struct OrganizationComponent *);
    void (*remove)(struct OrganizationComponent *, struct OrganizationComponent *);
    struct OrganizationComponent *(*get_child)(struct OrganizationComponent *, int);
    void (*operation)(struct OrganizationComponent *);
    int children_size;
    struct OrganizationComponent **children;
    // 如果是柔型数组,则自动扩展数组长度,但可能导致出现乱码现象,故采取固定长度数组
    // struct OrganizationComponent *children[];
} OrganizationComponent;
void add_component(OrganizationComponent *, OrganizationComponent *);
void remove_component(OrganizationComponent *, OrganizationComponent *);
OrganizationComponent *get_child_component(OrganizationComponent *, int);
void print_children(OrganizationComponent *children[], int children_size);

// 实现部件的树枝构件1
typedef struct CompanyComposite
{
    char name[200];
    void (*add)(struct OrganizationComponent *, struct OrganizationComponent *);
    void (*remove)(struct OrganizationComponent *, struct OrganizationComponent *);
    struct OrganizationComponent *(*get_child)(struct OrganizationComponent *, int);
    void (*operation)(struct CompanyComposite *);
    int children_size;
    struct OrganizationComponent **children;
} CompanyComposite;
CompanyComposite *company_composite_constructor(char *name);

// 实现部件的树枝构件2
typedef struct DepartmentComposite
{
    char name[200];
    void (*add)(struct OrganizationComponent *, struct OrganizationComponent *);
    void (*remove)(struct OrganizationComponent *, struct OrganizationComponent *);
    struct OrganizationComponent *(*get_child)(struct OrganizationComponent *, int);
    void (*operation)(struct DepartmentComposite *);
    int children_size;
    struct OrganizationComponent **children;
} DepartmentComposite;
DepartmentComposite *department_composite_constructor(char *name);

// 实现部件的叶子节点,叶子节点不能再含有子节点
typedef struct EmployeeLeaf
{
    char name[200];
    void (*add)(struct OrganizationComponent *, struct OrganizationComponent *);
    void (*remove)(struct OrganizationComponent *, struct OrganizationComponent *);
    struct OrganizationComponent *(*get_child)(struct OrganizationComponent *, int);
    void (*operation)(struct EmployeeLeaf *);
    int children_size;
    struct OrganizationComponent **children;
} EmployeeLeaf;
EmployeeLeaf *employee_leaf_constructor(char *name);

基础部件接口

// organization_component.c 定义部件接口或抽象类,分支和叶子节点遵循该类约定
#include "func.h"

// 定义部件接口或抽象类,分支和叶子节点遵循该类约定
// C语言没有接口和抽象类,用struct替代,同时把公共函数声明在这里

// 添加一个组件到子节点中
void add_component(OrganizationComponent *parent, OrganizationComponent *component)
{
  // 先将原数组保留下来
  OrganizationComponent **old_children = parent->children;
  parent->children_size += 1;
  // 新申请空间给子节点数组
  parent->children = (OrganizationComponent **)calloc(parent->children_size, sizeof(OrganizationComponent *));
  for (int i = 0; i < parent->children_size - 1; i++)
  {
    parent->children[i] = old_children[i];
  }
  // 将组件追加到子节点数组中
  parent->children[parent->children_size - 1] = component;
  free(old_children);
}

// 移除第一个匹配的子节点
void remove_component(OrganizationComponent *parent, OrganizationComponent *component)
{
  int size = parent->children_size;
  // 初始化组件id大于数组长度
  int com_idx = size;
  for (int i = 0; i < size; i++)
  {
    // 找到第一个匹配的组件下标
    if (parent->children[i] == component)
    {
      com_idx = i;
    }

    // 自匹配项开始,后项逐个往前移动1位
    if (i >= com_idx)
    {
      parent->children[i] = parent->children[i + 1];
      // 最后一项置空且总长度减少1位
      if (i == size - 1)
      {
        parent->children[i] = NULL;
        parent->children_size -= 1;
      }
    }
  }
}

// 打印全部子节点
void print_children(OrganizationComponent *children[], int children_size)
{
  for (int i = 0; i < children_size; i++)
  {
    printf("\r\n    children[%d]=%s", i, children[i]->name);
  }
}

// 根据下标获取子节点
OrganizationComponent *get_child_component(OrganizationComponent *component, int index)
{
  return component->children[index];
}

具体部件实现

// company_composite.c 实现部件的树枝构件1
#include "func.h"

// 实现部件的树枝构件1
void company_composite_operation(CompanyComposite *component)
{
  printf("\r\n CompanyComposite::operation() [name=%s]", component->name);
  print_children(component->children, component->children_size);
  for (int i = 0; i < component->children_size; i++)
  {
    if (component->children[i] != NULL)
    {
      component->children[i]->operation(component->children[i]);
    }
  }
}

// 创建CompanyComposite对象
CompanyComposite *company_composite_constructor(char *name)
{
  OrganizationComponent *component = (OrganizationComponent *)malloc(sizeof(OrganizationComponent));
  strncpy(component->name, name, 200);
  component->add = &add_component;
  component->remove = &remove_component;
  component->children_size = 0;
  component->get_child = &get_child_component;
  // 转为CompanyComposite
  CompanyComposite *company_composite = (CompanyComposite *)component;
  company_composite->operation = &company_composite_operation;
  return company_composite;
}
// department_composite.c  实现部件的树枝构件2
#include "func.h"

// 实现部件的树枝构件2
void department_composite_operation(DepartmentComposite *component)
{
  printf("\r\n DepartmentComposite::operation() [name=%s]", component->name);
  print_children(component->children, component->children_size);
  for (int i = 0; i < component->children_size; i++)
  {
    if (component->children[i] != NULL)
    {
      component->children[i]->operation(component->children[i]);
    }
  }
}

// 创建DepartmentComposite对象
DepartmentComposite *department_composite_constructor(char *name)
{
  OrganizationComponent *component = (OrganizationComponent *)malloc(sizeof(OrganizationComponent));
  strncpy(component->name, name, 200);
  component->add = &add_component;
  component->remove = &remove_component;
  component->children_size = 0;
  component->get_child = &get_child_component;
  // 转为DepartmentComposite
  DepartmentComposite *department_composite = (DepartmentComposite *)component;
  department_composite->operation = &department_composite_operation;
  return department_composite;
}
// employee_leaf.c 实现部件的叶子节点,叶子节点不能再含有子节点
#include "func.h"

// 实现部件的叶子节点,叶子节点不能再含有子节点

// 叶子节点不能再增加内容
void add_leaf_component(OrganizationComponent *parent, OrganizationComponent *component)
{
  printf("\r\n Leaf can't add.");
}

// 叶子节点没有移除内容
void remove_leaf_component(OrganizationComponent *parent, OrganizationComponent *component)
{
  printf("\r\n Leaf can't remove.");
}

// 叶子节点不能获取子节点
OrganizationComponent *get_leaf_child_component(OrganizationComponent *component, int index)
{
  printf("\r\n Leaf can't get_child.");
  return NULL;
}

// 子节点的操作函数
void employee_leaf_operation(EmployeeLeaf *component)
{
  printf("\r\n EmployeeLeaf::operation() [name=%s]", component->name);
}

// 创建EmployeeLeaf对象
EmployeeLeaf *employee_leaf_constructor(char *name)
{
  OrganizationComponent *component = (OrganizationComponent *)malloc(sizeof(OrganizationComponent));
  strncpy(component->name, name, 200);
  component->children_size = 0;
  component->add = &add_leaf_component;
  component->remove = &remove_leaf_component;
  component->get_child = &get_leaf_child_component;
  // 转为EmployeeLeaf
  EmployeeLeaf *employee_leaf = (EmployeeLeaf *)component;
  employee_leaf->operation = &employee_leaf_operation;
  return employee_leaf;
}

测试调用

   /**
    * 组合模式依据树形结构来组合对象,用不同组件来构建整体对象。
    * 不同组件之间有相同的接口约束,有不同的具体实现。
    * 先定义顶级节点,然后陆续加入枝叶节点和叶子节点,这样不断添加,将零散的个体组成一个整体。ss
    */

   // 通过组合模型组合了一个部件,分支和节点可以随意增删
   OrganizationComponent *com = (OrganizationComponent *)company_composite_constructor("西天旅游有限公司");
   OrganizationComponent *com1 = (OrganizationComponent *)department_composite_constructor("总裁办");
   OrganizationComponent *com2 = (OrganizationComponent *)department_composite_constructor("行动队");
   OrganizationComponent *com3 = (OrganizationComponent *)department_composite_constructor("后勤组");

   OrganizationComponent *leaf1 = (OrganizationComponent *)employee_leaf_constructor("唐三藏");
   OrganizationComponent *leaf2 = (OrganizationComponent *)employee_leaf_constructor("孙悟空");
   OrganizationComponent *leaf3 = (OrganizationComponent *)employee_leaf_constructor("猪悟能");
   OrganizationComponent *leaf4 = (OrganizationComponent *)employee_leaf_constructor("沙悟净");

   com->add(com, com1);
   com->add(com, com2);
   com->add(com, com3);

   // leaf1属于com1
   com1->add(com1, leaf1);
   // leaf2, leaf3属于com2
   com2->add(com2, leaf2);
   com2->add(com2, leaf3);

   // 添加再删除
   DepartmentComposite *dept1 = department_composite_constructor("小分队");
   com2->add(com2, (OrganizationComponent *)dept1);
   EmployeeLeaf *tmp1 = employee_leaf_constructor("临时工");
   dept1->add((OrganizationComponent *)dept1, (OrganizationComponent *)tmp1);
   dept1->remove((OrganizationComponent *)dept1, (OrganizationComponent *)tmp1);

   // leaf4属于com3
   com3->add(com3, leaf4);

   // 执行全部节点动作
   com->operation(com);

   // 获取某个节点
   OrganizationComponent *dept2 = com->get_child(com, 1);
   EmployeeLeaf *employee_child1 = (EmployeeLeaf *)dept2->get_child(dept2, 0);
   printf("\r\n [employee->name=%s]", employee_child1->name);

更多语言版本

不同语言设计模式源码源码,请查看:https://github.com/microwind/design-pattern