当前位置:网站首页>组合模式(Composite )
组合模式(Composite )
2022-06-26 12:40:00 【baboon_chen】
参考:
design-patterns-cpp/composite at master · JakubVojvoda/design-patterns-cpp · GitHub
一、什么是组合模式?
定义:将对象组合成树状的层次结构,使用户对
叶节点(单个对象)和树节点(组合对象)都有一致的访问性。
其中最关键的一点是,用户需要处理的对象能以层次结构表示。树本身就是一种具有递归性质的层次结构。如果树节点与叶节点都实现了相同的接口,那么无论树怎样扩展或裁减,都不会影响它被访问。
比如大部分国家的军队都采用层次结构管理。 每支部队包括几个师, 师由旅构成, 旅由团构成, 团可以继续划分为排。 最后, 每个排由一小队实实在在的士兵组成。 军事命令由最高层下达, 通过每个层级传递, 直到每位士兵都知道自己应该服从的命令。无论军队数量怎样变量,命令永远都下发。


二、实现
组合(Composite )模式包含以下主要角色:
- 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
- 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
- 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。
组合模式分为透明式的组合模式和安全式的组合模式。
1、透明方式
叶节点(Leaf)与树节点(Composite)都实现了抽象构件(Component)接口。如果Component中定义了Add()、Remove()、GetChild() 等方法,而叶节点都不需要,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。这样的好处就是客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。

/*
* C++ Design Patterns: Composite
* Author: Jakub Vojvoda [github.com/JakubVojvoda]
* 2016
*
* Source code is licensed under MIT License
* (for more details see LICENSE)
*
*/
#include <iostream>
#include <vector>
/*
* Component
* 为树叶构件和树枝构件声明公共接口
* 这里是透明式的组合模式,抽象构件还声明访问和管理子类的接口:Add\remove\getChild
*/
class Component
{
public:
virtual ~Component() {}
virtual Component *getChild( int )
{
return 0;
}
virtual void add( Component * ) { /* ... */ }
virtual void remove( int ) { /* ... */ }
virtual void operation() = 0;
};
/*
* Composite
* 是组合中的树节点对象,它有子节点,用于继承和实现抽象构件。
* 它的主要作用是存储和管理子部件
*/
class Composite : public Component
{
public:
~Composite()
{
for ( unsigned int i = 0; i < children.size(); i++ )
{
delete children[ i ];
}
}
Component *getChild( const unsigned int index )
{
return children[ index ];
}
void add( Component *component )
{
children.push_back( component );
}
void remove( const unsigned int index )
{
Component *child = children[ index ];
children.erase( children.begin() + index );
delete child;
}
void operation()
{
for ( unsigned int i = 0; i < children.size(); i++ )
{
children[ i ]->operation();
}
}
private:
std::vector<Component*> children;
};
/*
* Leaf
* 组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件
*/
class Leaf : public Component
{
public:
Leaf( const int i ) : id( i ) {}
~Leaf() {}
void operation()
{
std::cout << "Leaf "<< id <<" operation" << std::endl;
}
private:
int id;
};
int main()
{
Composite composite;
for ( unsigned int i = 0; i < 5; i++ )
{
composite.add( new Leaf( i ) );
}
composite.remove( 0 );
composite.operation();
return 0;
}
2、安全方式
仅在树节点中实现管理叶节点的方法(Add、Remove等)。

#include <iostream>
#include <vector>
class Component
{
public:
virtual ~Component() {}
virtual void operation() = 0;
};
class Composite : public Component
{
public:
~Composite()
{
for ( unsigned int i = 0; i < children.size(); i++ )
{
delete children[ i ];
}
}
Component *getChild( const unsigned int index )
{
return children[ index ];
}
void add( Component *component )
{
children.push_back( component );
}
void remove( const unsigned int index )
{
Component *child = children[ index ];
children.erase( children.begin() + index );
delete child;
}
void operation()
{
for ( unsigned int i = 0; i < children.size(); i++ )
{
children[ i ]->operation();
}
}
private:
std::vector<Component*> children;
};
class Leaf : public Component
{
public:
Leaf( const int i ) : id( i ) {}
~Leaf() {}
void operation()
{
std::cout << "Leaf "<< id <<" operation" << std::endl;
}
private:
int id;
};
int main()
{
Composite composite;
for ( unsigned int i = 0; i < 5; i++ )
{
composite.add( new Leaf( i ) );
}
composite.remove( 0 );
composite.operation();
return 0;
}
三、优缺点,适用场景
优点
- 组合模式使得客户端代码可以一致地处理单个对象和组合对象。
- 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足开闭原则。
缺点
- 设计较复杂,客户端需要花更多时间理清类之间的层次关系。
- 对于功能差异较大的类, 提供公共接口或许会有困难。
边栏推荐
- 心脏滴血漏洞(CVE-2014-0160)分析与防护
- 倍福PLC实现绝对值编码器原点断电保持---bias的使用
- 机器学习笔记 - 时间序列的季节性
- Don't mess with full_ Case and parallel_ CASE
- G - Cow Bowling
- Deeply analyze the differences between dangbei box B3, Tencent Aurora 5S and Xiaomi box 4S
- C# 结构体:定义、示例
- Processing function translate (mousex, mousey) learning
- 倍福PLC通过程序获取系统时间、本地时间、当前时区以及系统时间时区转换
- Record a phpcms9.6.3 vulnerability to use the getshell to the intranet domain control
猜你喜欢
随机推荐
C# const详解:C#常量的定义和使用
map 取值
Processing function translate (mousex, mousey) learning
倍福TwinCAT通过Emergency Scan快速检测物理连接和EtherCAT网络
C语言:练习题二
code force Party Lemonade
Electron official docs series: References
What are the common categories of software testing?
tauri vs electron
Explain C language 10 in detail (C language series)
Echart堆叠柱状图:色块之间添加白色间距效果设置
Power Designer - Custom Comment button
Electron official docs series: Best Practices
Copy multiple Excel files and name them different
第十章 设置结构化日志记录(二)
详细讲解C语言11(C语言系列)
. Net Maui performance improvement
LeetCode_栈_中等_150. 逆波兰表达式求值
Is it safe for the head teacher to open a stock account and open an account for financial management?
详细讲解C语言10(C语言系列)

![[BSidesCF 2019]Kookie 1](/img/22/585d081668e67b8389a1b90aaebe9d.png)




![HDU1724[辛普森公式求积分]Ellipse](/img/57/fb5098e150b5f3d91a5d0983a336ee.png)