目录
1、组合模式(Composite Pattern)含义
2、组合模式应用场景
3、组合模式的优缺点
4、组合模式的UML图学习
5、C++实现组合模式的简单示例(公司的OA系统)
1、组合模式(Composite Pattern)含义
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects uniformly.
将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。 (来自《设计模式之禅》)
2、组合模式应用场景
(1)当你发现需求中是体现部分与整体层次的结构时,例如文件系统,视图树,公司组织架构等;
(2)当你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就可以考虑组合模式;
3、组合模式的优缺点
(1)优点:
1)简化客户端代码:组合模式使得客户端可以统一对待单个对象和组合对象,无需区分它们的类型,从而简化了客户端的代码。
2)灵活性和可扩展性:通过组合模式,可以动态地添加、删除和修改对象的结构,使得系统更加灵活,并且易于扩展。
3)统一操作接口:组合模式定义了统一的操作接口,使得客户端可以一致地处理单个对象和组合对象,无需关心具体对象的类型。
4)便于创建复杂对象结构:组合模式可以将对象组织成树形结构,从而方便地创建和管理复杂的对象结构。
(2)缺点:
1)设计复杂性增加:使用组合模式会引入更多的类和对象,从而增加了系统的设计复杂性。这可能会导致代码结构变得复杂,不易理解和维护。
2)不适合所有场景:组合模式适用于表示整体-部分层次结构的情况,但并不是所有情况都适合使用组合模式。如果对象之间没有明显的层次关系或者不需要统一对待单个对象和组合对象,那么使用组合模式可能会带来不必要的复杂性。
3)难以限制组件类型:在组合模式中,组合对象可以包含其他组合对象或叶子对象。这意味着在编译时很难强制限制组件的类型,可能会导致一些运行时错误。
4)可能造成性能损失:由于组合模式涉及到递归遍历整个对象树,可能会导致性能上的一些损失。特别是当对象树非常庞大时,遍历操作可能会消耗较多的时间和资源。
尽管组合模式存在一些缺点,但它仍然是一种强大且常用的设计模式,特别适用于需要处理层次结构的场景。在使用组合模式时,需要根据具体的需求和系统设计来权衡其优缺点,并确保合理地应用该模式。
4、组合模式的UML图学习
组成元素:
(1)抽象构件角色(Composite):是组合中对象声明接口,实现所有类共有接口的默认行为。
(2)树叶构件角色(Leaf):上述提到的单个对象,叶节点没有子节点。
(3)树枝构件角色(Composite):定义有子部件的组合部件行为,存储子部件,在Component接口中实现与子部件有关的操作。
(4)客户端(Client):使用 Component 部件的对象。
5、C++实现组合模式的简单示例(公司的OA系统)
#include <iostream>
#include <string>
#include <vector>
// 组件接口
class Component
{
public:
virtual void display() const = 0;
};
// 叶子对象:员工
class Employee : public Component
{
private:
std::string name;
public:
Employee(const std::string& name) : name(name) {}
void display() const override
{
std::cout << "Employee: " << name << std::endl;
}
};
// 组合对象:部门
class Department : public Component
{
private:
std::string name;
std::vector<Component*> members;
public:
Department(const std::string& name) : name(name) {}
void add(Component* member)
{
members.push_back(member);
}
void remove(Component* member)
{
// 在实际应用中可能需要更复杂的逻辑来删除成员
members.erase(std::remove(members.begin(), members.end(), member), members.end());
}
void display() const override
{
std::cout << "Department: " << name << std::endl;
for (const auto& member : members)
{
member->display();
}
}
};
int main()
{
// 创建公司的组织结构
Department company("Company");
Department department1("Department 1");
Employee employee1("Employee 1");
Employee employee2("Employee 2");
Department department2("Department 2");
Employee employee3("Employee 3");
Employee employee4("Employee 4");
// 构建组织结构
company.add(&department1);
company.add(&department2);
department1.add(&employee1);
department1.add(&employee2);
department2.add(&employee3);
department2.add(&employee4);
// 显示公司的组织结构
company.display();
return 0;
}
在上述示例中,我们创建了一个 Component 接口作为组件的基类,其中包含了一个 display 方法。Employee 类表示叶子对象,Department 类表示组合对象。Department 类中使用了一个 vector 来存储成员。
在 main 函数中,我们创建了一个公司对象 company 和两个部门对象 department1 和 department2,以及四个员工对象 employee1、employee2、employee3 和 employee4。然后,将部门和员工添加到公司的组织结构中。最后,调用 company 的 display 方法,会递归地显示整个公司的组织结构。
运行以上代码,输出将会是:
Department: Company
Department: Department 1
Employee: Employee 1
Employee: Employee 2
Department: Department 2
Employee: Employee 3
Employee: Employee 4
可以看到,组合对象的 display 方法成功地递归调用了所有子组件的 display 方法,从而展示了公司的组织结构。
通过组合模式,我们可以以统一的方式管理和操作公司的组织结构,从而简化了代码的使用和维护。