组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

意图

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

主要解决

它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

何时使用

  1. 您想表示对象的部分-整体层次结构(树形结构)。
  2. 您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

如何解决

树枝和叶子实现统一接口,树枝内部组合该接口。

关键代码

树枝内部组合该接口,并且含有内部属性 List,里面放 Component。

应用实例

  1. 算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作数、操作符和另一个操作数。
  2. 在 JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。

优点

  1. 高层模块调用简单。
  2. 节点自由增加。

缺点

在使用组合模式时,其叶子和树枝的声明都是实例,而不是接口,违反了依赖倒置原则。

使用场景

部分、整体场景,如树形菜单,文件、文件夹的管理。

示例

员工的下属也是员工的集合,下面的示例中有5个员工A、B、C、D、E,B、C为A下属,D、E为B下属。假如需要对所有人增加1000工资,组合模式能同时使A和其下属生效。
image.png

  1. #include "pch.h"
  2. #include <iostream>
  3. #include <vector>
  4. #include <algorithm>
  5. class Employee
  6. {
  7. public:
  8. // 构造
  9. Employee(int ID, std::string name, int salary)
  10. : ID(ID)
  11. , name(name)
  12. , salary(salary)
  13. { }
  14. // 添加下属
  15. void Add(Employee* const e)
  16. {
  17. this->subordinates.push_back(e);
  18. }
  19. // 删除下属
  20. void Remove(const Employee* const e)
  21. {
  22. std::vector<Employee*>::iterator it = std::find(subordinates.begin(), subordinates.end(), e);
  23. this->subordinates.erase(it);
  24. }
  25. // 获取下属
  26. std::vector<Employee*> GetSubordinates()
  27. {
  28. return subordinates;
  29. }
  30. // 增加薪水
  31. void AddSalary(int salary)
  32. {
  33. this->salary += salary;
  34. for (Employee* e : subordinates)
  35. {
  36. e->AddSalary(salary);
  37. }
  38. }
  39. // 打印信息该节点信息,level用来控制最前面的空格使打印成树形结构
  40. void PrintInfo(int level=0)
  41. {
  42. for (int i = 0; i < level; ++i)
  43. {
  44. std::cout << " ";
  45. }
  46. std::cout << "[Name:" << this->name.c_str() << " Salary:" << this->salary << "]" << std::endl;
  47. for (Employee* e : subordinates)
  48. {
  49. e->PrintInfo(level + 1);
  50. }
  51. }
  52. bool operator== (const Employee* const e)
  53. {
  54. return this->ID == e->ID;
  55. }
  56. private:
  57. int ID;
  58. int salary;
  59. std::string name;
  60. std::vector<Employee*> subordinates;
  61. };
  62. /*--------------------------------
  63. A
  64. |
  65. +————B
  66. | |
  67. | +————D
  68. | |
  69. | +————E
  70. |
  71. +————C
  72. --------------------------------*/
  73. // 调用示例
  74. int main()
  75. {
  76. Employee A(1, "A", 20000);
  77. Employee B(2, "B", 13000);
  78. Employee C(3, "C", 10000);
  79. Employee D(4, "D", 10000);
  80. Employee E(5, "E", 12000);
  81. B.Add(&D);
  82. B.Add(&E);
  83. A.Add(&B);
  84. A.Add(&C);
  85. A.PrintInfo();
  86. std::cout << std::endl << "Add salary 1000 to all ..." << std::endl << std::endl;
  87. A.AddSalary(1000);
  88. A.PrintInfo();
  89. }
>>>
[Name:A Salary:20000]
  [Name:B Salary:13000]
    [Name:D Salary:10000]
    [Name:E Salary:12000]
  [Name:C Salary:10000]

Add salary 1000 to all ...

[Name:A Salary:21000]
  [Name:B Salary:14000]
    [Name:D Salary:11000]
    [Name:E Salary:13000]
  [Name:C Salary:11000]