当前位置: 首页 >  网技达人 >  【组合设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

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

导读:简介.组合模式(Composite.Pattern),又叫部分整体模式,是一种结构型设计模式。用于把一组类似的对象当作一个单一的对象来看。组合模式依据树形结构来组合对象,用不同组件来构建某个部分或整体对象。.如果你需要实现树状对象结构,可以使用组合模式。如果你希望客户端代码以相同

简介

组合模式(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

内容
  • 最新消息,powershell,10多年的癌症被治好了!
    最新消息,powershell,
    2023-12-10
    问:癌症是指什么?.答:.powershell一直有个特性,它的管道会传递对象,请看:.‘abc’ | ForEach-
  • RocketMQ消费者是如何负载均衡的
    RocketMQ消费者是如何负载
    2023-12-09
    摘要:RocketMQ 支持两种消息模式:集群消费( Clustering )和广播消费( Broadcasting )
  • Three.js教程:对象克隆、复制
    Three.js教程:对象克隆、
    2023-12-08
    推荐:将 NSDT场景编辑器 加入你的3D工具链.其他系列工具: NSDT简石数字孪生.对象克隆.clone()和复制.
  • FlashDuty Changelog 2023-09-07 | 新增深色模式与主题配置
    FlashDuty Change
    2023-12-04
    FlashDuty:一站式告警响应平台,前往此地址免费体验!.FlashDuty.现在已经全面支持了深色模式,这为您提供
  • 手表
    手表
    2024-01-20
    手表.产品功能.多功能数字显示:显示时间、*期、闹钟等.防水功能:可在浅水环境下使用,如洗手、下雨等.多种表带选择:可根
  • 儿童运动服
    儿童运动服
    2023-12-16
    儿童运动服.产品功能.我们的儿童运动服采用高品质的面料和工艺制作而成,具有出色的透气性和舒适性,可以让孩子在运动中保持干
  • T恤
    T恤
    2024-01-15
    T恤.产品功能.舒适的穿着感受.多种颜色和款式选择.适合多种场合穿着.可机洗.产品描述.我们的T恤采用100%优质棉质面
  • 短裤
    短裤
    2023-12-11
    时尚舒适,让您夏日更自在.产品功能.采用轻薄、透气的面料,给您清新舒适的穿着体验.弹性腰头设计,更贴合您的腰部曲线,穿着
  • 袜子
    袜子
    2023-12-26
    产品介绍.产品功能.我们的袜子采用了优质的天然材料,具有吸湿透气、舒适柔软的特点。特别设计的弹性帮助固定袜子位置,并且不
  • 皮鞋
    皮鞋
    2024-01-15
    皮鞋.产品介绍.我们的皮鞋是经过精心设计和**的高品质鞋类产品。采用优质皮革和精湛工艺,为您提供舒适的穿着体验和时尚的外
  • 儿童背带裤
    儿童背带裤
    2023-12-11
    儿童背带裤.产品功能.舒适性:儿童背带裤采用柔软舒适的面料,让宝宝在活动中感到自由自在。.便捷性:背带裤采用可调节的肩带
  • 短裤
    短裤
    2023-12-11
    时尚舒适,尽显运动魅力——短裤.产品功能.透气吸汗:采用透气材质制作,有效吸收汗液,让您在运动中保持干爽舒适。.伸缩自如
  • 婴儿连体衣
    婴儿连体衣
    2023-12-21
    婴儿连体衣.产品描述.婴儿连体衣是专门为婴儿设计的一款便捷舒适的睡衣,它将上衣和裤子融为一体,令宝宝在睡觉及活动时更加方
  • 风衣
    风衣
    2023-12-21
    风衣.产品功能.透气性高,能够有效排出体内热量和汗液,保持身体舒适.防风防水,能够有效阻挡外界风雨,保护身体不受天气影响