组合模式

理论

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

 

posted @   KYZH  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示

目录导航