重温设计模式--组合模式
文章目录
- 1 、组合模式(Composite Pattern)概述
- 2. 组合模式的结构
- 3. C++ 代码示例
- 4. C++示例代码2
- 5 .应用场景
1 、组合模式(Composite Pattern)概述
- 定义:组合模式是一种结构型设计模式,它允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
- 作用:
- 简化客户端代码:客户端可以统一地处理单个对象和对象组合,而不需要区分它们是单个的叶子节点还是包含多个子节点的组合节点。例如,在一个文件系统的表示中,客户端可以用相同的方式来处理文件(叶子节点)和文件夹(组合节点),如计算文件大小或显示文件/文件夹名称等操作。
- 层次结构表示:能够很好地表示具有层次结构的对象关系。比如公司的组织结构,一个部门(组合节点)可以包含多个子部门和员工(叶子节点),通过组合模式可以清晰地构建和遍历这种层次结构。
- 灵活的对象组合:可以方便地添加新的叶子节点或组合节点,构建出复杂的对象树,并且可以动态地修改这个树的结构,而不影响客户端对树的整体操作。
2. 组合模式的结构
- 组件(Component):这是组合模式中的抽象类或接口,它为组合中的对象(包括叶子节点和组合节点)定义了统一的接口,如操作方法、添加子节点方法(对于组合节点)、删除子节点方法(对于组合节点)等。
- 叶子(Leaf):叶子节点是组合中的最底层对象,它没有子节点,实现了组件接口定义的方法,但不包含添加或删除子节点相关的操作,因为它本身不能再包含其他对象。
- 组合(Composite):组合节点代表了包含子节点的对象,它实现了组件接口,并且内部维护了一个子节点列表。它的方法实现通常是遍历子节点列表,调用子节点的相应方法来完成操作,同时也实现添加和删除子节点的方法来管理子节点列表。
3. C++ 代码示例
- 以下以一个简单的图形绘制系统为例,图形可以是简单的基本图形(如圆形、矩形,相当于叶子节点),也可以是由多个图形组成的复杂图形(相当于组合节点)。
#include <iostream>
#include <vector>
// 组件抽象类
class Graphic
{
public:
virtual void draw() = 0;
virtual ~Graphic() {}
};
// 叶子节点:圆形
class Circle : public Graphic
{
public:
void draw()
{
std::cout << "绘制圆形" << std::endl;
}
};
// 叶子节点:矩形
class Rectangle : public Graphic
{
public:
void draw()
{
std::cout << "绘制矩形" << std::endl;
}
};
// 组合节点:复杂图形
class ComplexGraphic : public Graphic
{
private:
std::vector<Graphic*> graphics;
public:
void draw()
{
for (std::vector<Graphic*>::iterator it = graphics.begin(); it!= graphics.end(); ++it)
{
(*it)->draw();
}
}
void add(Graphic* graphic)
{
graphics.push_back(graphic);
}
void remove(Graphic* graphic)
{
for (std::vector<Graphic*>::iterator it = graphics.begin(); it!= graphics.end(); ++it)
{
if (*it == graphic)
{
graphics.erase(it);
break;
}
}
}
~ComplexGraphic()
{
graphics.clear();
}
};
int main()
{
// 创建叶子节点图形
Circle circle;
Rectangle rectangle;
// 创建组合节点图形并添加叶子节点图形
ComplexGraphic complexGraphic;
complexGraphic.add(&circle);
complexGraphic.add(&rectangle);
// 绘制组合图形,会依次绘制组合中的所有图形
complexGraphic.draw();
return 0;
}
在上述代码中:
Graphic
是组件抽象类,定义了draw
方法作为统一的接口,用于绘制图形。Circle
和Rectangle
是叶子节点类,它们分别实现了draw
方法来绘制具体的基本图形。ComplexGraphic
是组合节点类,内部维护了一个Graphic
指针的向量来存储子图形。draw
方法通过遍历子图形向量并调用每个子图形的draw
方法来绘制整个复杂图形,add
和remove
方法用于管理子图形列表。在main
函数中,首先创建了基本图形对象,然后创建了复杂图形对象并添加基本图形对象到其中,最后通过调用复杂图形对象的draw
方法来绘制整个组合图形,展示了组合模式在图形绘制系统中的简单应用。
4. C++示例代码2
#include<iostream>
#include<list>
#include<string>
using namespace std;
//将对象组合成树形结构以表示“部分-整体”的层次结构。
//组合模式使得用户对单个对象和组合对象的使用具有一致性
class Company
{
public:
Company(string name) { m_name = name; }
virtual ~Company(){}
virtual void Add(Company *pCom){}
virtual void Show(int depth) {}
protected:
string m_name;
};
//具体公司
class ConcreteCompany : public Company
{
public:
ConcreteCompany(string name): Company(name) {}
virtual ~ConcreteCompany() {}
void Add(Company *pCom) { m_listCompany.push_back(pCom); } //位于树的中间,可以增加子树
void Show(int depth)
{
for(int i = 0;i < depth; i++)
{
cout<<"-";
}
cout<<m_name<<endl;
list<Company *>::iterator iter=m_listCompany.begin();
for(; iter != m_listCompany.end(); iter++) //显示下层结点
{
(*iter)->Show(depth + 2);
}
}
private:
list<Company *> m_listCompany;
};
//具体的部门,财务部
class FinanceDepartment : public Company
{
public:
FinanceDepartment(string name):Company(name){}
virtual ~FinanceDepartment() {}
virtual void Show(int depth) //只需显示,无限添加函数,因为已是叶结点
{
for(int i = 0; i < depth; i++)
{
cout<<"-";
}
cout<<m_name<<endl;
}
};
//具体的部门,人力资源部
class HRDepartment :public Company
{
public:
HRDepartment(string name):Company(name){}
virtual ~HRDepartment() {}
virtual void Show(int depth) //只需显示,无限添加函数,因为已是叶结点
{
for(int i = 0; i < depth; i++)
{
cout<<"-";
}
cout<<m_name<<endl;
}
};
int main()
{
Company *root = new ConcreteCompany("总公司");
Company *leaf1=new FinanceDepartment("财务部");
Company *leaf2=new HRDepartment("人力资源部");
root->Add(leaf1);
root->Add(leaf2);
//分公司A
Company *mid1 = new ConcreteCompany("分公司A");
Company *leaf3=new FinanceDepartment("财务部");
Company *leaf4=new HRDepartment("人力资源部");
mid1->Add(leaf3);
mid1->Add(leaf4);
root->Add(mid1);
//分公司B
Company *mid2=new ConcreteCompany("分公司B");
FinanceDepartment *leaf5=new FinanceDepartment("财务部");
HRDepartment *leaf6=new HRDepartment("人力资源部");
mid2->Add(leaf5);
mid2->Add(leaf6);
root->Add(mid2);
root->Show(0);
delete leaf1; delete leaf2;
delete leaf3; delete leaf4;
delete leaf5; delete leaf6;
delete mid1; delete mid2;
delete root;
return 0;
}
输出:
总公司
--财务部
--人力资源部
--分公司A
----财务部
----人力资源部
--分公司B
----财务部
----人力资源部
请按任意键继续. . .
组合模式让客户一致的使用组合结构和单个对象,他们的接口是统一透明的,这样用户就无须做判断,然后根据不同的结果去执行不同的动作了。
5 .应用场景
- 文件系统和目录结构表示
- 描述层次关系:文件系统是典型的树形层次结构,由文件(叶子节点)和文件夹(组合节点)组成。组合模式可以很好地对其进行建模。例如,在操作系统的文件管理器中,每个文件夹可以包含文件和子文件夹,使用组合模式可以用统一的方式处理文件和文件夹的操作,如计算文件夹大小(需要递归计算子文件夹和文件的大小)、显示文件和文件夹列表、复制或移动文件夹(包括其内部的所有文件和子文件夹)等操作。
- 权限管理:对于文件系统的访问权限设置,权限可以从文件夹继承到文件。通过组合模式,可以方便地为文件夹(组合节点)设置权限,并将这些权限传播给其包含的文件(叶子节点)和子文件夹,确保整个文件系统层次结构的权限一致性。
- 图形用户界面(GUI)组件层次结构
- 构建界面布局:在GUI设计中,窗口、面板(如容器面板)是组合节点,而按钮、文本框等是叶子节点。组合模式用于构建复杂的用户界面布局。例如,一个窗口可以包含多个面板,每个面板又可以包含按钮、文本框等各种控件。通过组合模式,可以方便地添加、删除或重新排列这些界面组件,并且可以对整个界面或部分组件进行统一的操作,如显示、隐藏、设置样式等。
- 事件处理和消息传递:在GUI系统中,事件(如鼠标点击、键盘输入)需要在组件层次结构中传播。组合模式可以帮助实现事件从顶层窗口向下传递到具体的叶子节点组件,或者从底层组件向上冒泡到父容器组件,从而实现合理的事件处理机制。
- 组织结构和资源管理
- 企业组织结构建模:企业的组织结构是一个层次分明的体系,包括部门(组合节点)和员工(叶子节点)。组合模式可以用于表示这种组织结构,方便进行资源分配、任务分配等操作。例如,人力资源部门可以通过组合模式表示的组织结构,为整个公司(根节点)或者某个部门(子组合节点)统一进行工资核算、培训安排等操作,这些操作可以递归地应用到部门内的所有员工(叶子节点)。
- 计算机集群资源管理:在计算机集群环境中,集群(组合节点)由多个计算节点(叶子节点)组成。通过组合模式,可以对集群资源进行统一管理,如分配任务到集群(将任务分配到具体的计算节点)、监控集群状态(包括各个计算节点的状态)、进行软件安装和更新(在集群范围内或者部分计算节点范围内)等操作。
- 游戏开发中的场景和对象管理
- 游戏场景构建:游戏场景通常包含各种游戏对象,如角色(叶子节点)、道具(叶子节点)和地形(组合节点,可能包含多个子地形区域)等。组合模式可以用于构建游戏场景,方便游戏开发者添加、删除或修改游戏场景中的对象。例如,在一个角色扮演游戏中,可以通过组合模式创建一个包含多个区域(组合节点)的大地图场景,每个区域又包含角色、道具等对象,对整个场景或者部分区域的操作(如渲染、碰撞检测等)可以通过组合模式统一进行。
- 游戏对象层次关系处理:游戏中的一些对象可能具有父子关系,如角色装备(叶子节点)与角色本身(组合节点)。通过组合模式,可以更好地处理这种对象层次关系,例如,当角色移动时,其装备也随之移动;当角色受到攻击时,其装备的属性(如防御值)可以对攻击进行响应,这种对象之间的关联和操作可以通过组合模式来清晰地实现。