Composite Pattern
组合模式
考虑一个系统,存在层次管理关系,例如公司内董事长之下,有多个经理,每个经理之下都由若干个部门,每个部分都若干个员工,如果采用面向对象的思想来设计这样一个树状的系统?
建立统一基类对象:Component
分类:内节点(枝干),外节点(叶子)
特点:(1)内节点可以有孩子,外节点不可以有孩子;(2)内节点的孩子可以是内节点,也可以是孩子
区别:和数据结构中的递归定义树对比,叶子是不可以拥有孩子的,叶子不可能成为内节点,这是一开始就设计好的,哪些是叶子,哪些是枝干,对象之间的组合只需要枝干添加孩子即可。但这也成为瓶颈之一,因为如果日后叶子需要新添部门,或者需要再次细分,改动不易,解决思路有 II ——(1)初始设计中,决定不会再细分的部分才定义为叶子,一定会细分或者可能细分的部分一定要定义为枝干(2)如果后续对叶子一定要再次细分,只需要替换叶子的父节点的孩子即可,并把原来的孩子删除,不过这样就需要保存父节点,较浪费空间。
大致模式如下:
基类定义:
class Component {
public:
virtual ~Component() = default;
// 添加孩子(附属)
virtual void addChild(Component *const child) = 0;
// 删除孩子
virtual void removeChild(Component *const child) = 0;
// 获取第 index 个孩子
virtual Component* getChild(const int index) = 0;
// 访问自己以及自己的孩子
virtual void visit() = 0;
} ;
叶子定义:
class Leaf : public Component {
public:
virtual void addChild(Component *const child) {
/* forbidden */
}
virtual void removeChild(Component *const child) {
/* forbidden */
}
virtual Component* getChild(const int index) {
/* forbidden */
return nullptr;
}
virtual void visit() {
/*
访问叶子节点
*/
}
} ;
枝干定义:
class Trunk : public Component {
public:
virtual void addChild(Component *const child) {
/* find 去重 */
childs.emplace_back(child);
}
virtual void removeChild(Component *const child) {
/*
找到 child, 然后 erase, 以及 delete child
*/
}
virtual Component* getChild(const int index) {
return index >= childs.size() ? nullptr : childs[index];
}
virtual void visit() {
/*
遍历容器, 逐个访问孩子
*/
}
private:
std::vector<Component*> childs;
} ;
适用场景:
(1)树形结构系统
(2)需要忽略内节点和外节点差异