组合模式
定义:
组合多个对象形成树形结构,实现部分-整体的层次关系
优点:
(1)很清楚的定义树形层次,结点和叶结点进行分割,便于扩展
(2)很灵活的递归组合
缺点:
(1)扩展的对象需要满足抽象接口的约束,相互间具有依赖关系
(2)组合深度很大时创建会很麻烦,也会创建很多的子对象
(3)类型转换时避免截断
使用范围:
满足树形结构,且子结点也可做为下一个组合的根节点(类似于容器);
案例:文件树、json解析
结构:
实现一个文件树的增删,包括文件和文件夹2中类型。
文件相当于叶结点;文件夹相当于子结点,子结点可以增加子结点和叶节点
实现:
namespace structural_pattern
{
class composite_pattern
{
public:
virtual void get_status() = 0;
virtual void add_composite(composite_pattern* comp) {};
virtual void remove_composite(composite_pattern* comp) {};
public:
short file_type;
unsigned long file_id;
};
class file_composite_pattern : public composite_pattern
{
public:
file_composite_pattern(short file_type, unsigned long file_id)
{
this->file_id = file_id;
this->file_type = file_type;
}
void get_status() override
{
std::cout << "type[" << file_type <<"] id["<< file_id<<"]"<<std::endl;
}
};
class folder_composite_pattern : public composite_pattern
{
public:
folder_composite_pattern(short file_type, unsigned long file_id)
{
this->file_id = file_id;
this->file_type = file_type;
}
void get_status() override
{
std::cout << "type[" << file_type << "] id[" << file_id << "]" << std::endl;
for each (auto var in list_comp)
{
#define FILE_NUM 10000
for (auto i = var.get()->file_id / FILE_NUM;i; --i)
{
std::cout << "----";
}
var.get()->get_status();
}
}
void add_composite(composite_pattern* comp)
{
list_comp.push_back(std::shared_ptr<composite_pattern>(comp));
std::cout << "add " << "type[" << comp->file_type << "] id[" << comp->file_id << "]" << std::endl;
}
void remove_composite(composite_pattern* comp)
{
for (auto itr = list_comp.begin(); itr != list_comp.end(); ++itr)
{
if (itr->get()->file_id == comp->file_id && itr->get()->file_type == comp->file_type)
{
list_comp.erase(itr);
std::cout<<"earse "<< "type[" << comp->file_type << "] id[" << comp->file_id << "]" << std::endl;
}
}
}
private:
std::vector<std::shared_ptr<composite_pattern>>list_comp{};
};
}
测试:
基于GoogleTest 的单元测试框架;框架可参考如下网址:
https://www.cnblogs.com/jycboy/p/gtest_catalog.html
using namespace structural_pattern;
TEST(test_composite_pattern_add_composite, success_add_show)
{
composite_pattern* c00 = new folder_composite_pattern(2, 00000);
composite_pattern* c11 = new file_composite_pattern(1, 10001);
composite_pattern* c12 = new folder_composite_pattern(2, 10002);
composite_pattern* c21 = new file_composite_pattern(1, 20001);
composite_pattern* c22 = new folder_composite_pattern(2, 20002);
composite_pattern* c31 = new file_composite_pattern(1, 30001);
composite_pattern* c13 = new file_composite_pattern(1, 10003);
c22->add_composite(c31);
c12->add_composite(c21);
c12->add_composite(c22);
c00->add_composite(c11);
c00->add_composite(c12);
c00->add_composite(c13);
c00->get_status();
}
总结
(1)满足部分-整体层次关系才能使用这种设计模式
(2)考虑树的深度和广度,避免在内存创建过多的子对象
(3)增加新的构件类型需要考虑与结点的依赖关系