当前位置:网站首页>组合模式(Composite Pattern)
组合模式(Composite Pattern)
2022-06-28 09:25:00 【初学小白Lu】
定义
将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
动机
当你发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合对象结构中的所有对象时,就应该考虑用组合模式了。
UML类图

- Component抽象构建角色, 定义参加组合独享的共同方法和属性,可以定义一些默认的行为或者属性
- Leaf叶子结构,旗下没有分支,是最小的遍历单位
- Composite树枝结构,作用是组合树枝节点和叶子结点形成的树形结构
优点
高层模块调用简单,所有结点都是Component ,局部和整体对调用者来说没有任何区别,高层不必关心自己处理的是单个对象还是整个组合结构。
结点自由增加,使用组合模式,如果想增加树枝节点,树叶结点都很容易,只要找到父节点就行,符合开闭原则。
缺点
树枝和树叶结点使用时的定义,直接使用的是实现类。违背依赖倒置原则。
使用场景
维护和展示一部分-整体关系的场景:eg树形菜单,文件和文件夹管理。
从一个整体中能够独立出部分模块和功能的场景。
注意事项
只要是树形结构,就考虑组合模式,只要体现这你部分关系,就使用组合模式
Composite 模式在实现中有一个问题就是要提供对于子节点( Leaf)的管理策略,这里使用的是 STL 中的 vector,可以提供其他的实现方式,如数组、链表、 Hash 表等。
示例

以一个大型公司为需求背景,组织我们的代码。一个北京总公司,下面有郑州和西安两个分公司。然后每个公司不管是总公司还是分公司都有自己的人力资源部,IT部和市场部。
// component.h
#ifndef COMPONENT_H
#define COMPONENT_H
#include <QList>
class Component
{
public:
Component(QString name);
virtual ~Component();
virtual void add(Component* com, int depth = 0) = 0;
virtual void remove(Component* com) = 0;
virtual void display() = 0;
virtual void LineOfDuty() = 0;
QString name();
void setDepth(int depth);
int depth();
private:
QString m_Name;
int m_Depth;
};
class ConcreteCompany : public Component
{
public:
ConcreteCompany(QString name);
virtual ~ConcreteCompany();
virtual void add(Component* com, int depth = 0);
virtual void remove(Component* com);
virtual void display();
virtual void LineOfDuty();
private:
QList<Component*> m_ChildCom;
};
class HumanResource : public Component
{
public:
HumanResource(QString name);
virtual ~HumanResource();
virtual void add(Component* com, int depth = 0);
virtual void remove(Component* com);
virtual void display();
virtual void LineOfDuty();
};
class IT : public Component
{
public:
IT(QString name);
virtual ~IT();
virtual void add(Component* com, int depth = 0);
virtual void remove(Component* com);
virtual void display();
virtual void LineOfDuty();
};
class Marketing : public Component
{
public:
Marketing(QString name);
virtual ~Marketing();
virtual void add(Component* com, int depth = 0);
virtual void remove(Component* com);
virtual void display();
virtual void LineOfDuty();
};
#endif // COMPONENT_H
// component.cpp
/************************************ * @brief : 安排一下故事背景:有一个王者农药全国总公司在深圳,现在想要在全国开办事处 * 1.北京办事处- 招聘部,研发部,市场部 * 2.郑州办事处- 招聘部,研发部,市场部 * 3.西安办事处- 招聘部,研发部,市场部 * and so on... * @author : wzx * @date : 2020-05-11 * @project : Composite *************************************/
#include <QDebug>
#include "component.h"
#define DELETEOBJECT(x) if(x) {
delete x; x = nullptr; }
Component::Component(QString name):m_Name(name) {
}
Component::~Component(){
}
QString Component::name()
{
return m_Name;
}
void Component::setDepth(int depth)
{
m_Depth = depth;
}
int Component::depth()
{
return m_Depth;
}
ConcreteCompany::ConcreteCompany(QString name)
: Component(name)
{
}
ConcreteCompany::~ConcreteCompany()
{
for(auto com : m_ChildCom)
{
DELETEOBJECT(com);
}
m_ChildCom.clear();
}
void ConcreteCompany::add(Component* com, int depth)
{
com->setDepth(depth);
m_ChildCom.append(com);
}
void ConcreteCompany:: remove(Component* com)
{
m_ChildCom.removeOne(com);
}
void ConcreteCompany::display()
{
QString str;
for(int n = 0; n < depth(); ++n)
str += "--";
qDebug() << qPrintable(str) << (name());
for(auto com : m_ChildCom)
{
com->display();
}
}
void ConcreteCompany::LineOfDuty()
{
}
HumanResource::HumanResource(QString name)
: Component(name)
{
}
HumanResource::~HumanResource()
{
}
void HumanResource::add(Component* com, int depth)
{
com->setDepth(depth);
}
void HumanResource::remove(Component* com)
{
}
void HumanResource::display()
{
QString str;
for(int n = 0; n < depth(); ++n)
str += "--";
qDebug() << qPrintable(str) << (name());
}
void HumanResource::LineOfDuty()
{
qDebug() << "人力资源部,负责招聘";
}
IT::IT(QString name)
: Component(name)
{
}
IT::~IT()
{
}
void IT::add(Component* com, int depth)
{
com->setDepth(depth);
}
void IT::remove(Component* com)
{
}
void IT::display()
{
QString str;
for(int n = 0; n < depth(); ++n)
str += "--";
qDebug() << qPrintable(str) << (name());
}
void IT::LineOfDuty()
{
qDebug() << "IT部门,负责写代码";
}
Marketing::Marketing(QString name)
: Component(name)
{
}
Marketing::~Marketing()
{
}
void Marketing::add(Component* com, int depth)
{
com->setDepth(depth);
}
void Marketing::remove(Component* com)
{
}
void Marketing::display()
{
QString str;
for(int n = 0; n < depth(); ++n)
str += "--";
qDebug() << qPrintable(str) << name();
}
void Marketing::LineOfDuty()
{
qDebug() << "市场部门,负责市场推广";
}
// main.cpp
#include <QCoreApplication>
#include <QDebug>
#include "component.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Component* root = new ConcreteCompany("北京总部");
root->setDepth(0);
root->add(new HumanResource("人力资源部门"), 1);
root->add(new IT("IT部门"), 1);
root->add(new Marketing("市场部门"), 1);
Component* zz = new ConcreteCompany("郑州办事处");
zz->add(new HumanResource("人力资源部门"), 2);
zz->add(new IT("IT部门"), 2);
zz->add(new Marketing("市场部门"), 2);
root->add(zz, 1);
Component* xa = new ConcreteCompany("西安办事处");
xa->add(new HumanResource("人力资源部门"), 2);
xa->add(new IT("IT部门"), 2);
xa->add(new Marketing("市场部门"), 2);
root->add(xa, 1);
root->display();
return a.exec();
}
运行结果
"北京总部"
-- "人力资源部门"
-- "IT部门"
-- "市场部门"
-- "郑州办事处"
---- "人力资源部门"
---- "IT部门"
---- "市场部门"
-- "西安办事处"
---- "人力资源部门"
---- "IT部门"
---- "市场部门"
示例二
算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作数也可以是操作数、操作符和另一个操作数。
边栏推荐
- Boundary value analysis method for learning basic content of software testing (2)
- 全局异常处理器与统一返回结果
- Implementation of single sign on
- Calculation of stock purchase and sale expenses
- 2020-10-27
- Dbeaver connects to kingbasees V8 (ultra detailed graphic tutorial)
- Understanding the IO model
- The digital human industry is about to break out. What is the market pattern?
- 手机炒股开户安不安全?
- PMP考试重点总结五——执行过程组
猜你喜欢

How to reduce the risk of project communication?

虚拟机14安装win7(图教程)

Resource scheduling and task scheduling of spark

Screen settings in the source code of OBS Live Room

Expérience d'optimisation SQL: de 30248 secondes à 0001 secondes

From knowledge to wisdom: how far will the knowledge map go?

DBeaver安装与使用教程(超详细安装与使用教程)
![1180: fractional line delimitation /p1068 [noip2009 popularization group] fractional line delimitation](/img/1a/162b060a6498e58278b6ca50e4953c.png)
1180: fractional line delimitation /p1068 [noip2009 popularization group] fractional line delimitation

买卖股票费用计算

For the development of short video app, the elder warned me to choose the open source code
随机推荐
Implementation of single sign on
Importerror: no module named image [duplicate] - importerror: no module named image [duplicate]
2022-06-27:给出一个长度为n的01串,现在请你找到两个区间, 使得这两个区间中,1的个数相等,0的个数也相等, 这两个区间可以相交,但是不可以完全重叠
abnormal
怎样在手机上开户?现在网上开户安全么?
Android studio interview preparation
Apiccloud, together with 360 Tianyu, helps enterprises keep the "first pass" of APP security
Do static code blocks always execute first? The pattern is smaller!!!
I want to register my stock account online. How do I do it? Is online account opening safe?
JDBC connection database (MySQL) steps
JVM系列(2)——垃圾回收
PMP Exam key summary VI - chart arrangement
2020-10-27
什么是在线开户?现在网上开户安全么?
Regular verification of mobile phone number and email [easy to understand]
手机号、邮箱正则验证[通俗易懂]
Resource scheduling and task scheduling of spark
JVM family (2) - garbage collection
买卖股票费用计算
Data mining modeling practice