合成/聚合复用原则
在进行功能拓展时,应首先考虑合成/聚合,其次采用继承。
- 合成:一种较强的‘包含’关系,严格的部分和整体的关系,有相同的生命周期。如:大雁与翅膀
- 聚合:一种较弱的‘包含’关系,种类上的包含,A包含B,B不一定包含与A。如:大雁与雁群
- 可以有效的控制类层次的规模。
桥接模式
将抽象与实现分离,是它们可以独立变化。
抽象与实现分离并非抽象基类与派生类之间的关系。抽象是指产品的不同分类方法;实现指具体产品。如:手机的各种品牌是抽象,而具体手机的软件则是实现。
举个例子: 我们有OPPO与VIVO两种手机,每种手机上的软件大同小异,有两种基本功能:打电话、玩游戏。如果使用继承机制按树形继承,当我们需要增加品牌或功能时,需要产生大量的类。我们发现手机与软件之间是一种“聚合”关系。也就是,手机需要有多个软件组成.在两个相对独立的基类中,其实隐含着一个一对多的关系,我们可一使用合成/聚合原则将其解耦开来。完成对类层次规模的控制。
图中可以看出,‘桥’是指聚合桥(一对多),桥的左边是抽象,包含的一方为主体,桥的右边是实现。
我们发现,若按照继承的方案来做,应该是cellphone->brand->software的三层结构,合成/聚合复用原则就是尽可能用类之间的组合来代替继承.
#include <iostream>
#ifndef _DESIGN_PATTERN_BRIDGE_SOFTWARE_HPP_
#define _DESIGN_PATTERN_BRIDGE_SOFTWARE_HPP_
namespace design_pattern
{
class Software
{
public:
virtual void Operation() = 0;
virtual ~Software() {}
};
class CallSoftware : public Software
{
public:
void Operation()
{
std::cout << "Calling xxx!!!" << std::endl;
}
};
class GameSoftware : public Software
{
public:
void Operation()
{
std::cout << "Playing Game!!!" << std::endl;
}
};
}
#endif // !_DESIGN_PATTERN_BRIDGE_SOFTWARE_HPP_
#include "software.hpp"
#ifndef _DESIGN_PATTERN_BRIDGE_BRAND_HPP_
#define _DESIGN_PATTERN_BRIDGE_BRAND_HPP_
namespace design_pattern
{
class Brand
{
protected:
Software *psoft_;
public:
void set_psoft(Software * const ptr)
{
psoft_ = ptr;
}
virtual void Operation() = 0;
virtual ~Brand() {}
};
class OPPO : public Brand
{
public:
void Operation()
{
psoft_->Operation();
}
};
class VIVO : public Brand
{
public:
void Operation()
{
psoft_->Operation();
}
};
}
#endif // !_DESIGN_PATTERN_BRIDGE_BRAND_HPP_
//bridge_main.cpp
#include "brand.hpp"
#include "software.hpp"
#include <memory>
#include <typeinfo>
using std::cout;
using std::endl;
using std::unique_ptr;
using std::make_unique;
using namespace design_pattern;
int main()
{
unique_ptr<Software> ptr(new CallSoftware);
OPPO oppo;
Brand *poppo = &oppo;
cout << ptr.get() << endl;
poppo->set_psoft(ptr.get());
poppo->Operation();
ptr.reset(new GameSoftware);
VIVO vivo;
Brand *pvivo = &vivo;
pvivo->set_psoft(ptr.get());
pvivo->Operation();
return 0;
}
语法tips
- std中的智能指针对有继承关系的类使用时,智能指针不具有继承关系,所以先进行类型转换,在make_xxx生成智能指针。
- C++运行时类型查看
- 头文件
- typeid(var).name()