一、简介
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
上图中的对象组:
红色的对象是包含其他的对象组的对象,在树状结构中,为非叶子节点
黑色的对象是不再包含其他对象组的对象,在树状结构中,为叶子节点
组合模式创建了一个可以包含自己对象组的类。该类提供了修改或查询相同对象组的方式。
二、实例
【项目说明】
上述描述可能比较抽象, 我们使用生活中的一个例子说明:(可以结合下面代码理解)
假如某顾客在某电商超市里购买了一系列物品(3支牙刷、一件方便面、洗手液一瓶、书籍3本:C++沉思录、C和指针、计算机网络),超市老板在拣货过程中,对该顾客的购买物品进行打包处理(把3支牙刷放到一个盒子,3本书放到一个盒子里,其他物品不再打包,最后把所有物品放入快递箱子)。
例如这种复杂的订单,我们可以把其拆分为为各部分组成:
包含商品等的盒子(下列代码中的Box类),类似非叶子节点
商品(下列代码中的Commodity类),类似叶子结点
并且不同结构的部分可以使用一通用结构:物品(Object)表示
Box和Commodity都是Object,这样,组合模式就能使用Object类将所有对象组合成树状结构,并且能像使用独立对象一样使用它们。
我们知道每件商品都具有价格属性,作为单独的对象,无论是Box或Commodity,都能利用递归查询内包含的对象列表_objList的方式单独获取该对象的价值。
【代码实现】
1)抽象基类-Object 提供一种通用结构,声明子类可以实现的行为
class Object
{
public:
virtual ~Object() {}
virtual void add(Object *obj) {};
virtual void remove(Object *obj) {};
virtual double showAndPrice() = 0;
};
2)子类Box类,继承Object。作为非叶子节点,具有对象列表_objList,并实现添加和删除其他Object对象的功能
class Box : public Object
{
public:
Box(string name) : _boxName(name){}
~Box() {}
void add(Object *obj)
{
_objList.push_back(obj);
}
void remove(Object *obj)
{
_objList.remove(obj);
}
double showAndPrice()
{
cout << "包裹-" << _boxName << ":" << endl;
double price = 0;
for (auto it : _objList)
{
price += it->showAndPrice();
}
cout << "共" << price << "元" << endl << endl;
return price;
}
private:
string _boxName; //盒子名称
std::list<Object*> _objList; //内容物列表
};
3)商品类Commodity,继承Object。作为叶子结点,没有可以包含其他对象的功能,所以没有内容对象列表,但是具有价格属性
//单件商品
class Commodity : public Object
{
public:
Commodity(string name, double price)
:_name(name)
,_price(price) {}
double showAndPrice()
{
cout << "商品:" << _name << " " << _price << "元" << endl;
return _price;
}
private:
string _name; //商品名称
double _price; //商品价格
};
4)使用
int main(int argc, char *argv[])
{
//某顾客购物清单
Object* cd1 = new Commodity("牙刷A", 3.5);
Object* cd2 = new Commodity("牙刷B", 3.5);
Object* cd3 = new Commodity("牙刷C", 3.5);
Object* cd4 = new Commodity("X牌方便面", 20);
Object* cd5 = new Commodity("洗手液", 15.8);
Object* cd6 = new Commodity("书籍:C++沉思录", 38);
Object* cd7 = new Commodity("书籍:C和指针 ", 32);
Object* cd8 = new Commodity("书籍:计算机网络 ", 65);
//商店打包:书籍放一个箱子
Object* box1 = new Box("书籍箱子");
box1->add(cd6);
box1->add(cd7);
box1->add(cd8);
//商店打包:牙刷放一个盒子
Object* box2 = new Box("牙刷盒子");
box2->add(cd1);
box2->add(cd2);
box2->add(cd3);
//其他物品不再另行包装
//打包成一个箱子快递邮走
Object* box = new Box("快递箱子");
box->add(box1);
box->add(box2);
box->add(cd4);
box->add(cd5);
//查看购物清单
cout << "总价格为:" << box->showAndPrice() << endl;
system("pause");
return 0;
}
5)运行结果
【参考&致谢】