组合模式
理论
组合模式(Composite),将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
透明方式与安全方式
透明方式:在 Leaf 类当中也有 Add 和 Remove 方法。这种方式叫做透明方式,在 Compoment 中声明所有用来管理子对象的方法,其中包括 Add、Remove 等。这样实现 Component 接口的所有子类都具备了 Add 和 Remove。这样做的好处就是叶节点和枝结点对于外界没有区别,它们具备完全一致的行为接口。但问题也很明显,因为 Leaf 类本身不具备 Add()、Remove() 方法的功能,所以实现它是没有意义的。
安全方式:在 Leaf 类当中不用 Add 和 Remove方法。在 Component 接口中不去声明 Add 和 Remove 方法,那么子类的 Leaf 就不需要去实现它,而是在 Composite 声明所有用来管理子类对象的方法,这样就不会出现透明方式中的问题。不过由于不够透明,所以树叶和树枝类将不具有相同的接口,客户端的调用需要做相应的判断,带来了不变。
组合模式的应用场景
1. 当需求中是体现部分与整体层次的结构时
2. 希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中地所有对象时
组合模式的优点
组合模式定义包含了基本对象和组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象。
因此用户不用关心到底是处理一个叶节点还是处理一个组合组件,也就不需要为定义组合而写一些选择判断语句。
组合模式让客户可以一致地使用组合结构和单个对象。
实例
模拟公司管理系统如下图
特征:整体与部分可以被一致对待
UML类图
代码实现
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #include <iostream> #include <list> using namespace std; //公司类 (抽象类) class Company { public : Company(string _name) :name(_name) {} virtual void Add(Company* c) = 0; //增加 virtual void Remove(Company* c) = 0; //移除 virtual void Display( int depth) = 0; //显示 virtual void LineOfDuty() = 0; //旅行职责 protected : string name; }; //其他公司类 实现接口 树枝结点 class ConcreteCompany : public Company{ public : ConcreteCompany(string _name) :Company(_name) {} virtual void Add(Company* c){ children.push_back(c); } void Remove(Company* c) { children. remove (c); } virtual void Display( int depth) { string s(depth, '-' ); cout << s << name << endl; for (list<Company*>::iterator it = children.begin(); it != children.end(); it++) { (*it)->Display(depth + 2); } } virtual void LineOfDuty() { for (list<Company*>::iterator it = children.begin(); it != children.end(); it++) { (*it)->LineOfDuty(); } } private : list<Company*> children; }; //人力资源部与财务部类 树叶结点 class HRDepartment : public Company { public : HRDepartment(string _name) :Company(_name) {} virtual void Add(Company* c) {} virtual void Remove(Company* c) {} virtual void Display( int depth) { string s(depth, '-' ); cout << s << name << endl; } virtual void LineOfDuty() { cout << name << " 员工招聘培训管理" << endl; } }; //财务部 class FinanceDepartment : public Company { public : FinanceDepartment(string _name) :Company(_name) {} virtual void Add(Company* c) {} virtual void Remove(Company* c) {} virtual void Display( int depth) { string s(depth, '-' ); cout << s << name << endl; } virtual void LineOfDuty() { cout << name << " 公司财务收支管理" << endl; } }; //客户端调用 int main() { 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( "南京办事处财务部" )); comp->Add(comp1); ConcreteCompany* comp2 = new ConcreteCompany( "杭州办事处" ); comp2->Add( new HRDepartment( "杭州办事处人力资源部" )); comp2->Add( new FinanceDepartment( "杭州办事处财务部" )); comp->Add(comp2); cout << "结构图:" << endl; root->Display(1); cout << endl; cout << "职责:" << endl; root->LineOfDuty(); delete root; delete comp; delete comp1; delete comp2; system ( "pause" ); return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?