设计模式C++组合
注:参考视频:【设计模式(完整版)】2.3组合_哔哩哔哩_bilibili
分类:(对象)结构型
树形结构.可以当做数据结构中的森林看待.
问题:复杂订单的计算,有两类对象:产品和盒子.一个盒子中可以包含多个产品或多个小盒子.这些小盒子中同样可以包含一些产品或更小的盒子,以此类推.
1.组件(Component)接口描述了树中简单项目和复杂项目所共有的操作.
2.叶节点(leaf)是树的基本结构,它不包含子项目.
3.容器(Container)--又名"组合(Composite)"--是包含叶节点或其他容器等子项目的单位.
4.客户端(Client)通过组件接口与所有项目交互.
举个例子:如下图,记事本中查看中有一个菜单状态栏和子菜单缩放,子菜单缩放中有放大缩小恢复默认缩放.
共同的execute()都是鼠标焦点置于上面.leaf就是各个功能,而Composite就是缩放.
解决方案:将对象组成树形结构以表示"部分-整体"的层次结构.使得用户对单个对象和组合对象的使用具有一致性.
另一个例子:借助组合模式在图形编辑器中实现一系列的几何图形
既可以空白画布上可以画圆,亦可以在已经有复杂图案上的画布上添加一个圆.都依赖画布这个接口.
优点:
可以利用多态和递归机制更方便地使用复杂树结构,
开闭原则:无需更改现有代码,就可以在应用中添加新元素,使其成为对象树的一部分.
缺点:
对于功能差异较大的类,提供公共接口或许会有困难,在特定情况下,需要过度一般化组件接口,使其变得令人难以理解.(不要硬套组合这个设计模式)
代码:
#include <iostream>
#include <list>
#include <string>
//接口:不管是商品还是盒子,都依赖这个接口
class OrderNode
{
protected:
OrderNode* m_parent;
float m_price;
public:
virtual ~OrderNode() {}
virtual bool isComposite() const
{
return false;
}
virtual std::string operation() = 0;
//ADD,Remove不放到接口里,保持和类图一致
OrderNode() :m_parent(nullptr), m_price(0.0f)
{
}
OrderNode(OrderNode* m_parent,float price) :m_parent(m_parent), m_price(price)
{
}
void setParent(OrderNode* node)
{
m_parent = node;
}
OrderNode* getParent()
{
return m_parent;
}
void setPrice(float price)
{
m_price = price;
}
float getPrice()
{
return m_price;
}
};
//产品
class Product :public OrderNode
{
public:
~Product() {}
Product(float price) :OrderNode(nullptr,price) {}
virtual std::string operation()override
{
return "产品";
}
};
//盒子
class Box :public OrderNode
{
protected:
std::list<OrderNode*> m_children;
public:
~Box() {}
Box() {}
bool isComposite() const override
{
return true;
}
void Add(OrderNode* node)
{
m_children.push_back(node);
node->setParent(this);
m_price += node->getPrice();
}
void Remove(OrderNode* node)
{
//注意:只是从容器里移除.
m_children.remove(node);
node->setParent(nullptr);
m_price -= node->getPrice();
}
virtual std::string operation() override
{
std::string result;
m_price = 0;
//c即可能是盒子也可能是产品,是盒子就递归
for (auto c : m_children)
{
if (c == m_children.back())
{
result += c->operation();
}
else
{
result += c->operation() + '+';
}
m_price += c->getPrice();
}
return "盒子("+result+")";
}
};
void clientCode(OrderNode* node)
{
std::cout << "结构:" << node->operation() << std::endl;
std::cout << "价格:" << node->getPrice() << std::endl;
}
int main()
{
std::cout << "#处理叶子节点....." << std::endl;
Product leaf(5.0f);
clientCode(&leaf);
std::cout << "\n\n";
std::cout << "#处理组合节点..." << std::endl;
Box tree;
Box branch1;
Box branch2;
Product leaf1(5.0f);
Product leaf2(5.0f);
Product leaf3(5.0f);
tree.Add(&branch1);
tree.Add(&branch2);
branch1.Add(&leaf1);
branch1.Add(&leaf2);
branch2.Add(&leaf3);
clientCode(&tree);
std::cout << "\n\n";
tree.Add(&leaf);
clientCode(&tree);
}