目录
后面的模式内容代码是参考其他博客的( 23种设计模式),版权原因就不公开了哈,自己没事看看
第二部分:结构型模式
1. Decorator模式
Decorator提供了一种给类增加职责的方法,不是通过继承实现的,而是通过组合。
在结构图中,ConcreteComponent和Decorator需要有同样的接口,因此ConcreteComponent和Decorator有着一个共同的父类。更直观的思路可能是decorator直接继承concrete-component,但这样会导致继承过于的深。直接继承component,然后在concrete decorator中添加装饰。
1). 代码实现
component.h
#ifndef COMPONENT_H
#define COMPONENT_H
#include <string>
using namespace std;
// 所有饮料的基类
class IBeverage
{
public:
virtual string Name() = 0; // 名称
virtual double Cost() = 0; // 价钱
};
#endif // COMPONENT_H
concrete component.h
#ifndef CONCRETE_COMPONENT_H
#define CONCRETE_COMPONENT_H
#include "component.h"
/********** 具体的饮料(咖啡)**********/
// 黑咖啡,属于混合咖啡
class HouseBlend : public IBeverage
{
public:
string Name() {
return "HouseBlend";
}
double Cost() {
return 30.0;
}
};
// 深度烘培咖啡豆
class DarkRoast : public IBeverage
{
public:
string Name() {
return "DarkRoast";
}
double Cost() {
return 28.5;
}
};
#endif // CONCRETE_COMPONENT_H
decorator.h
#ifndef DECORATOR_H
#define DECORATOR_H
#include "component.h"
// 调味品
class CondimentDecorator : public IBeverage
{
public :
CondimentDecorator(IBeverage *beverage) : m_pBeverage(beverage) {}
string Name() {
return m_pBeverage->Name();
}
double Cost() {
return m_pBeverage->Cost();
}
protected :
IBeverage *m_pBeverage;
} ;
#endif // DECORATOR_H
#ifndef CONCRETE_DECORATOR_H
#define CONCRETE_DECORATOR_H
#include "decorator.h"
/********** 具体的饮料(调味品)**********/
// 奶油
class Cream : public CondimentDecorator
{
public:
Cream(IBeverage *beverage) : CondimentDecorator(beverage) {}
string Name() {
return m_pBeverage->Name() + " Cream";
}
double Cost() {
return m_pBeverage->Cost() + 3.5;
}
};
// 摩卡
class Mocha : public CondimentDecorator
{
public:
Mocha(IBeverage *beverage) : CondimentDecorator(beverage) {}
string Name() {
return m_pBeverage->Name() + " Mocha";
}
double Cost() {
return m_pBeverage->Cost() + 2.0;
}
};
// 糖浆
class Syrup : public CondimentDecorator
{
public:
Syrup(IBeverage *beverage) : CondimentDecorator(beverage) {}
string Name() {
return m_pBeverage->Name() + " Syrup";
}
double Cost() {
return m_pBeverage->Cost() + 3.0;
}
};
#endif // CONCRETE_DECORATOR_H
main.cpp
#include "concrete_component.h"
#include "concrete_decorator.h"
#include <iostream>
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif
int main()
{
/********** 黑咖啡 **********/
IBeverage *pHouseBlend = new HouseBlend();
cout << pHouseBlend->Name() << " : " << pHouseBlend->Cost() << endl;
// 黑咖啡 + 奶牛
CondimentDecorator *pCream = new Cream(pHouseBlend);
cout << pCream->Name() << " : " << pCream->Cost() << endl;
// 黑咖啡 + 摩卡
CondimentDecorator *pMocha = new Mocha(pHouseBlend);
cout << pMocha->Name() << " : " << pMocha->Cost() << endl;
// 黑咖啡 + 糖浆
CondimentDecorator *pSyrup = new Syrup(pHouseBlend);
cout << pSyrup->Name() << " : " << pSyrup->Cost() << endl;
/********** 深度烘培咖啡豆 **********/
IBeverage *pDarkRoast = new DarkRoast();
cout << pDarkRoast->Name() << " : " << pDarkRoast->Cost() << endl;
// 深度烘培咖啡豆 + 奶油
CondimentDecorator *pCreamDR = new Cream(pDarkRoast);
cout << pCreamDR->Name() << " : " << pCreamDR->Cost() << endl;
// 深度烘培咖啡豆 + 奶油 + 摩卡
CondimentDecorator *pCreamMocha = new Mocha(pCreamDR);
cout << pCreamMocha->Name() << " : " << pCreamMocha->Cost() << endl;
// 深度烘培咖啡豆 + 奶油 + 摩卡 + 糖浆
CondimentDecorator *pCreamMochaSyrup = new Syrup(pCreamMocha);
cout << pCreamMochaSyrup->Name() << " : " << pCreamMochaSyrup->Cost() << endl;
SAFE_DELETE(pSyrup);
SAFE_DELETE(pMocha);
SAFE_DELETE(pCream);
SAFE_DELETE(pHouseBlend);
SAFE_DELETE(pCreamMochaSyrup);
SAFE_DELETE(pCreamMocha);
SAFE_DELETE(pCreamDR);
SAFE_DELETE(pDarkRoast);
getchar();
return 0;
}
2) 优缺点
- 优点:可以实现和继承同样的功能,但相对于继承更加灵活,可以创造出更多的产品组合
缺点:有很多小类 - 让Decorator直接维护一个指向ConcreteComponent引用(指针)不就可以达到同样的效果,答案是肯定并且是否定的。肯定的是你可以通过这种方式实现,否定的是你不要用这种方式实现,因为通过这种方式你就只能为这个特定的ConcreteComponent提供修饰操作了,当有了一个新的ConcreteComponent你又要去新建一个Decorator来实现。但是通过结构图中的ConcreteComponent和Decorator有一个公共基类,就可以利用OO中多态的思想来实现只要是Component型别的对象都可以提供修饰操作的类,这种情况下你就算新建了100个Component型别的类。ConcreteComponent,也都可以由Decorator一个类搞定。这也正是Decorator模式的关键和威力所在了。
- ConcreteDecorator给ConcreteComponent类添加了动作AddedBehavior。
2. Composite模式
在开发中,我们经常可能要递归构建树状的组合结构,Composite模式则提供了很好的解决方案。
1). 结构图
2). 实例
client
#include "composite.h"
#include "leaf.h"
int main()
{
// 创建一个树形结构
// 创建根节点
Component *pRoot = new Composite("江湖公司(任我行)");
// 创建分支
Component *pDepart1 = new Composite("日月神教(东方不败)");
pDepart1->Add(new Leaf("光明左使(向问天)"));
pDepart1->Add(new Leaf("光明右使(曲洋)"));
pRoot->Add(pDepart1);
Component *pDepart2 = new Composite("五岳剑派(左冷蝉)");
pDepart2->Add(new Leaf("嵩山(左冷蝉)"));
pDepart2->Add(new Leaf("衡山(莫大)"));
pDepart2->Add(new Leaf("华山(岳不群)"));
pDepart2->Add(new Leaf("泰山(天门道长)"));
pDepart2->Add(new Leaf("恒山(定闲师太)"));
pRoot->Add(pDepart2);
// 添加和删除叶子
pRoot->Add(new Leaf("少林(方证大师)"));
pRoot->Add(new Leaf("武当(冲虚道长)"));
Component *pLeaf = new Leaf("青城(余沧海)");
pRoot->Add(pLeaf);
// 小丑,直接裁掉
pRoot->Remove(pLeaf);
// 递归地显示组织架构
pRoot->Operation(1);
// 删除分配的内存
SAFE_DELETE(pRoot);
getchar();
return 0;
}
component.h
#ifndef COMPONENT_H
#define COMPONENT_H
#include <iostream>
#include <string>
using namespace std;
class Component
{
public:
Component(string name) : m_strName(name) {}
virtual ~Component() {}
virtual void Add(Component *cmpt) = 0; // 添加构件
virtual void Remove(Component *cmpt) = 0; // 删除构件
virtual Component* GetChild(int index) = 0; // 获取构件
virtual void Operation(int indent) = 0; // 显示构件(以缩进的方式)
Component()=delete; // 不允许
protected:
string m_strName;
};
#endif // COMPONENT_H
#ifndef COMPOSITE_H
#define COMPOSITE_H
#include <vector>
#include "component.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif
class Composite : public Component
{
public:
Composite(string name) : Component(name) {}
virtual ~Composite() {
while (!m_elements.empty()) {
vector<Component*>::iterator it = m_elements.begin();
SAFE_DELETE(*it);
m_elements.erase(it);
}
}
void Add(Component *cmpt) {
m_elements.push_back(cmpt);
}
void Remove(Component *cmpt) {
vector<Component*>::iterator it = m_elements.begin();
while (it != m_elements.end()) {
if (*it == cmpt) {
SAFE_DELETE(cmpt);
m_elements.erase(it);
break;
}
++it;
}
}
Component* GetChild(int index) {
if (index >= m_elements.size())
return NULL;
return m_elements[index];
}
// 递归显示
void Operation(int indent) {
string newStr(indent, '-');
cout << newStr << "+ " << m_strName << endl;
// 显示每个节点的孩子
vector<Component*>::iterator it = m_elements.begin();
while (it != m_elements.end()) {
(*it)->Operation(indent + 2);
++it;
}
}
private:
Composite(); // 不允许
private:
vector<Component *> m_elements;
};
#endif // COMPOSITE_H
// 透明组合模式
#ifndef LEAF_H
#define LEAF_H
#include "component.h"
class Leaf : public Component
{
public:
Leaf(string name) : Component(name) {}
virtual ~Leaf() {}
void Add(Component *cmpt) {
cout << "Can't add to a Leaf" << endl;
}
void Remove(Component *cmpt) {
cout << "Can't remove from a Leaf" << endl;
}
Component* GetChild(int index) {
cout << "Can't get child from a Leaf" << endl;
return NULL;
}
void Operation(int indent) {
string newStr(indent, '-');
cout << newStr << " " << m_strName << endl;
}
private:
Leaf(); // 不允许
};
#endif // LEAF_H
3). 讨论
- Composite模式在实现中有一个问题就是要提供对于子节点(Leaf)的管理策略,这里使用的是STL 中的vector,可以提供其他的实现方式,如数组、链表、Hash表等。
- 容易在组合体内增加对象部件。客户端不必因加入了新的部件而更改代码。有利于功能的扩展。
定义了“部分-整体”的层次结构,基本对象可以被组合成更大的对象,而且这种操作是可重复的,不断重复下去就可以得到一个非常大的组合对象,但这些组合对象与基本对象拥有相同的接口,因而组合是透明的,用法完全一致。 - Composite模式通过和Decorator模式有着类似的结构图,但是Composite模式旨在构造类,而Decorator模式重在不生成子类即可给对象添加职责。Decorator模式重在修饰,而Composite模式重在表示。
3. Flyweight模式
1)结构图
用于创建对象,特别是对于大量轻量级的对象,不可能每个对象都设计一个类,这样会造成很大的存储开销。因此我们设计一个 对象工厂,该工厂种有一个容器保存所有对象,这些对象通过flyweight来管理,flyweight管理的状态可以分为内部状态和外部状态两部分,内部状态就是不变化的部分,外部状态可以通过外部传参构建。下面的代码实例中任务类型就是内部状态,武器就是外部状态,可以随时通过外部接口进行更改。
Flyweight模式中有一个类似Factory模式的对象构造工厂FlyweightFactory,当客户程序员(Client)需要一个对象时候就会向FlyweightFactory发出请求对象的消息GetFlyweight()消息,FlyweightFactory拥有一个管理、存储对象的“仓库”(或者叫对象池,vector实现),GetFlyweight()消息会遍历对象池中的对象,如果已经存在则直接返回给Client,否则创建一个新的对象返回给Client。当然可能也有不想被共享的对象(例如结构图中的UnshareConcreteFlyweight),但不在本模式的讲解范围.
2) 代码实现
main.cpp
#include "concrete_flyweight.h"
#include "flyweight_factory.h"
#include <ctime>
std::map<std::string, IPlayer*> PlayerFactory::m_map = std::map<std::string, IPlayer*>();
// 玩家类型和武器
static std::string s_playerType[2] = { "T", "CT" };
static std::string s_weapons[4] = { "AK-47", "Maverick", "Gut Knife", "Desert Eagle" };
#define GET_ARRAY_LEN(array, len) {len = (sizeof(array) / sizeof(array[0]));}
int main()
{
srand((unsigned)time(NULL));
int playerLen;
int weaponsLen;
GET_ARRAY_LEN(s_playerType, playerLen);
GET_ARRAY_LEN(s_weapons, weaponsLen);
// 假设,游戏中有十位玩家
for (int i = 0; i < 10; i++) {
// 获取随机玩家和武器
int typeIndex = rand() % playerLen;
int weaponIndex = rand() % weaponsLen;
std::string type = s_playerType[typeIndex];
std::string weapon = s_weapons[weaponIndex];
// 获取玩家
IPlayer *p = PlayerFactory::getPlayer(type);
// 从武器库中随机分配武器
p->assignWeapon(weapon);
// 派玩家去执行任务
p->mission();
}
getchar();
return 0;
}
#ifndef FLYWEIGHT_H
#define FLYWEIGHT_H
#include <iostream>
#include <string>
// 玩家 - 有武器和使命
class IPlayer
{
public:
virtual ~IPlayer() {}
// 分配武器
virtual void assignWeapon(std::string weapon) = 0;
// 使命
virtual void mission() = 0;
protected:
std::string m_task; // 内部状态
std::string m_weapon; // 外部状态
};
#endif // FLYWEIGHT_H
#ifndef CONCRETE_FLYWEIGHT_H
#define CONCRETE_FLYWEIGHT_H
#include "flyweight.h"
// 恐怖分子
class Terrorist : public IPlayer
{
public:
Terrorist() {
m_task = "Plant a bomb";
}
virtual void assignWeapon(std::string weapon) override {
m_weapon = weapon;
}
virtual void mission() override {
std::cout << "Terrorist with weapon " + m_weapon + "," + " Task is " + m_task << std::endl;
}
};
// 反恐精英
class CounterTerrorist : public IPlayer
{
public:
CounterTerrorist() {
m_task = "Diffuse bomb";
}
virtual void assignWeapon(std::string weapon) override {
m_weapon = weapon;
}
virtual void mission() override {
std::cout << "Counter Terrorist with weapon " + m_weapon + "," + " Task is " + m_task << std::endl;
}
};
#endif // CONCRETE_FLYWEIGHT_H
#ifndef FLYWEIGHT_FACTORY_H
#define FLYWEIGHT_FACTORY_H
#include "concrete_flyweight.h"
#include <map>
// 用于获取玩家
class PlayerFactory
{
public:
// 如果 T/CT 对象存在,则直接从享元池获取;否则,创建一个新对象并添加到享元池中,然后返回。
static IPlayer* getPlayer(std::string type)
{
IPlayer *p = NULL;
if (m_map.find(type) != m_map.end()) {
p = m_map[type];
}
else {
// 创建 T/CT 对象
if (type == "T") {
std::cout << "Terrorist Created" << std::endl;
p = new Terrorist();
}
else if (type == "CT") {
std::cout << "Counter Terrorist Created" << std::endl;
p = new CounterTerrorist();
}
else {
std::cout << "Unreachable code!" << std::endl;
}
// 一旦创建,将其插入到 map 中
m_map.insert(std::make_pair(type, p));
}
return p;
}
private:
// 存储 T/CT 对象(享元池)
static std::map<std::string, IPlayer*> m_map;
};
#endif // FLYWEIGHT_FACTORY_H
3)讨论
我们在State模式和Strategy模式中会产生很多的对象,因此我们可以通过Flyweight模式来解决这个问题。
4.Facade模式
1)结构图
Façade模式的想法、思路和实现都非常简单,但是其思想却是非常有意义的。并且Façade设计模式在实际的开发设计中也是应用最广、最多的模式之一。
Façade为子系统提供了一个更高层的调用接口,是对子系统一些功能的封装,使得子系统更加容易使用。
Client需要不同子系统功能的组合,Facade相当于一个代理,提供一个更上层的接口,一步就完成这个任务。不需要客户还要了解子系统的结构和之间的调用流程了。
2)实例
Client想要知道订单状态,但其实订单会经历提交给订单团队-》提交给供应商-》提交给快递员三个步骤,分别在三个子系统中实现,这里通过facade进行封装,就只需要简单调用一个checkStatus就可以得到结果了,使用方便。
#include "facade.h"
int main()
{
OnlineShoppingFacade facade;
// 提交订单
facade.submitRequest();
// 跟踪订单,直到订单完成
while (!facade.checkStatus());
std::cout << "********** 订单完成,跟踪次数:" << facade.followupNum() << " **********" << std::endl;
getchar();
return 0;
}
Facade,这里是重点,把子系统相关功能封装
#ifndef FACADE_H
#define FACADE_H
#include "sub_system.h"
// 网购外观
class OnlineShoppingFacade
{
public:
OnlineShoppingFacade() {
m_nCount = 0;
}
// 返回跟踪次数
int followupNum() {
return m_nCount;
}
// 提交订单
void submitRequest() {
m_nState = 0;
}
// 跟踪订单
bool checkStatus(){
// 收到订单请求
switch (m_nState) {
case Received:
m_nState++;
// 将请求转发给订单团队
m_order.submitRequest();
std::cout << "********** 提交给订单团队,跟踪次数:" << m_nCount << " **********" << std::endl;
break;
case SubmittedToOrderTeam:
// 如果订单团队完成验证,则向供应商发出请求
if (m_order.checkStatus()) {
m_nState++;
m_vendor.submitRequest();
std::cout << "********** 提交给供应商,跟踪次数:" << m_nCount << " **********" << std::endl;
}
break;
case SubmittedToVendor:
// 如果供应商已将包裹打包,将其转发给快递员
if (m_vendor.checkStatus()) {
m_nState++;
m_courier.submitRequest();
std::cout << "********** 提交给快递员,跟踪次数:" << m_nCount << " **********" << std::endl;
}
break;
case SubmittedToCourier:
// 如果包裹交付,订单完成
if (m_courier.checkStatus())
return true;
default:
break;
}
m_nCount++;
// 订单未完成
return false;
}
private:
enum States {
Received, // 收到
SubmittedToOrderTeam, // 提交给订单团队
SubmittedToVendor, // 提交给供应商
SubmittedToCourier // 提交给快递员
};
int m_nState; // 订单状态
int m_nCount; // 跟踪次数
OrderTeam m_order;
Vendor m_vendor;
Courier m_courier;
};
#endif // FACADE_H
子系统状态实现
#ifndef SUB_SYSTEM_H
#define SUB_SYSTEM_H
#include <iostream>
#include <string>
#include <windows.h>
const std::string c_stateToStrCourier[] = { "收到", "验证可达性", "分配人员", "派送包裹", "获取交货确认", "完成" };
const std::string c_stateToStrVendor[] = { "收到", "确认库存", "从仓库得到物品", "包装", "联系快递员", "完成" };
const std::string c_stateToStrOrderTeam[] = { "收到", "确认付款", "联系供应商", "完成" };
const int c_nMsec = 300; // 休眠时间(毫秒) - Sleep(c_nMsec) 处可以替换为一些有用的代码
// 订单团队
class OrderTeam
{
public:
void submitRequest() {
m_nState = 0;
}
// 检测状态
bool checkStatus() {
std::cout << "订单团队 - 当前状态:" << c_stateToStrOrderTeam[m_nState] << std::endl;
Sleep(c_nMsec);
m_nState++;
return (m_nState == Complete);
}
private:
enum States {
Received, // 收到
VerifyPayment, // 确认付款
ContactVendor, // 联系供应商
Complete // 完成
};
int m_nState;
};
// 供应商
class Vendor
{
public:
void submitRequest() {
m_nState = 0;
}
// 检测状态
bool checkStatus() {
std::cout << "供应商 - 当前状态:" << c_stateToStrVendor[m_nState] << std::endl;
Sleep(c_nMsec);
m_nState++;
return (m_nState == Complete);
}
private:
enum States {
Received, // 收到
VerifyInventory, // 确认库存
GetItemFromWareHouse, // 从仓库得到物品
PackItem, // 包装
ContactCourier, // 联系快递员
Complete // 完成
};
int m_nState;
};
// 快递员
class Courier
{
public:
// 将请求转发给快递员
void submitRequest() {
m_nState = 0;
}
// 检测状态
bool checkStatus() {
std::cout << "快递员 - 当前状态:" << c_stateToStrCourier[m_nState] << std::endl;
Sleep(c_nMsec);
m_nState++;
return (m_nState == Complete);
}
private:
enum States {
Received, // 收到
VerifyReachbility, // 验证可达性
AssignPerson, // 分配人员
DispatchPackage, // 派送包裹
GetDeliveryConfirmation, // 获取交货确认
Complete // 完成
};
int m_nState;
};
#endif // SUB_SYSTEM_H
3)讨论
Façade模式在高层提供了一个统一的接口,解耦了系统。设计模式中还有另一种模式Mediator也和Façade有类似的地方。但是Mediator主要目的是对象间的访问的解耦(通讯时候的协议),具体请参见Mediator文档。
5. Proxy模式
1)结构图
一个对象不能直接访问另一个对象,通过代理起到一个中介的作用来实现目的,就是一个代理商嘛。
应用场景:
- 创建开销大的对象时候,比如显示一幅大的图片,我们将这个创建的过程交给代理去完成,自己做其他事
- 为网络上的对象创建一个局部的本地代理,比如要操作一个网络上的一个对象(网络性能不好的时候,问题尤其突出),我们将这个操纵的过程交给一个代理去完成
- 对对象进行控制访问的时候,比如在Jive论坛中不同权限的用户(如管理员、普通用户等)将获得不同层次的操作权限,我们将这个工作交给一个代理去完成,GoF称之为保护代理(Protection Proxy)。
2)实例
client,找个电信运营代理商,进行充值服务
#include "proxy.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif
int main()
{
unique_ptr<ITelco> sub = new CMCC;
Proxy* proxy = new Proxy(sub.get());
proxy->Recharge(20);
proxy->Recharge(100);
SAFE_DELETE(proxy);
getchar();
return 0;
}
抽象类:
#ifndef SUBJECT_H
#define SUBJECT_H
// 电信运营商
class ITelco
{
public:
virtual ~ITelco() {}
virtual void Recharge(int money) = 0; // 充值
};
#endif // SUBJECT_H
ConcreteSubject
#ifndef REAL_SUBJECT_H
#define REAL_SUBJECT_H
#include "subject.h"
#include <iostream>
// 中国移动
class CMCC : public ITelco
{
public:
void Recharge(int money) override {
std::cout << "Recharge " << money;
}
};
#endif // REAL_SUBJECT_H
proxy和ConcreteSubject中国移动沟通,Client不必访问CMCC
#ifndef PROXY_H
#define PROXY_H
#include "subject.h"
#include "real_subject.h"
#include <iostream>
// 代理点
class Proxy : public ITelco
{
public:
Proxy(ITelco* pITelco) : m_pCMCC(pITelco) {}
~Proxy() { delete m_pCMCC; }
// 低于 50 不充
void Recharge(int money) override {
if (money >= 50) {
if (m_pCMCC == NULL)
m_pCMCC = new CMCC();
m_pCMCC->Recharge(money);
}
else {
std::cout << "Sorry, too little money" << std::endl;
}
}
private:
ITelco *m_pCMCC;
};
#endif // PROXY_H
3)讨论
- Proxy模式最大的好处就是实现了逻辑和实现的彻底解耦。
6. Bridge模式
1)结构图
将抽象部分与实现部分分离,使他们都可以独立的发生变化
Abstraction(抽象类):里面包含 Implementor 实现类的指针,如开关,里面有一个指向电器的指针
RefinedAbstraction(扩充抽象类):具体的开关,可以扩充开关功能,不同的开关功能可能不同
Implementor(实现类接口):电器抽象类,与abstract不一定一致,自己按照电器类型定义
ConcreteImplementor(具体实现类):不同的电器有不同的功能
在Bridge模式的结构图中可以看到,系统被分为两个相对独立的部分,左边是抽象部分,右边是实现部分,这两个部分可以互相独立地进行修改:如增加了一个新电器,只需在右面加一个电器就好了,原来的开关都可以用于控制这个电器,开关不用改。如果通过继承来实现,开关A派生出两个电器A00,A01,又有新的开关A1控制A00,A01,如果只有一个基类A的话,这样就会形成一个树形结构,越来越庞大,一致继承继承,多重继承。所以抽象出一个实现类B电器类。
实际上上面使用Bridge模式和使用带来问题方式的解决方案的根本区别在于是通过继承还是通过组合的方式去实现一个功能需求
2) 代码实现
https://blog.csdn.net/liang19890820/article/details/79501177
电器和开关的例子
Client
#include "refined_abstraction.h"
#include "concrete_implementor.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif
int main()
{
// 创建电器 - 电灯、风扇
IElectricalEquipment *light = new Light();
IElectricalEquipment *fan = new Fan();
/**
* 创建开关 - 拉链式开关、两位开关
* 将拉链式开关和电灯关联起来,将两位开关和风扇关联起来
**/
ISwitch *pullChain = new PullChainSwitch(light);
ISwitch *twoPosition = new TwoPositionSwitch(fan);
// 开灯、关灯
pullChain->On();
pullChain->Off();
// 打开风扇、关闭风扇
twoPosition->On();
twoPosition->Off();
SAFE_DELETE(twoPosition);
SAFE_DELETE(pullChain);
SAFE_DELETE(fan);
SAFE_DELETE(light);
getchar();
return 0;
}
Abstract
#ifndef ABSTRACTION_H
#define ABSTRACTION_H
#include "implementor.h"
// 开关
class ISwitch
{
public:
ISwitch(IElectricalEquipment *ee) { m_pEe = ee; }
virtual ~ISwitch() {}
// 打开电器
virtual void On() = 0;
// 关闭电器
virtual void Off() = 0;
protected:
IElectricalEquipment *m_pEe;
};
#endif // ABSTRACTION_H
refined absraction
#ifndef REFINED_ABSTRACTION_H
#define REFINED_ABSTRACTION_H
#include "abstraction.h"
#include <iostream>
// 拉链式开关
class PullChainSwitch : public ISwitch
{
public:
PullChainSwitch(IElectricalEquipment *ee) : ISwitch(ee) {}
// 用拉链式开关打开电器
virtual void On() override {
std::cout << "Switch on the equipment with a pull chain switch." << std::endl;
m_pEe->PowerOn();
}
// 用拉链式开关关闭电器
virtual void Off() override {
std::cout << "Switch off the equipment with a pull chain switch." << std::endl;
m_pEe->PowerOff();
}
};
// 两位开关
class TwoPositionSwitch : public ISwitch
{
public:
TwoPositionSwitch(IElectricalEquipment *ee) : ISwitch(ee) {}
// 用两位开关打开电器
virtual void On() override {
std::cout << "Switch on the equipment with a two-position switch." << std::endl;
m_pEe->PowerOn();
}
// 用两位开关关闭电器
virtual void Off() override {
std::cout << "Switch off the equipment with a two-position switch." << std::endl;
m_pEe->PowerOff();
}
};
#endif // REFINED_ABSTRACTION_H
implementor
#ifndef IMPLEMENTOR_H
#define IMPLEMENTOR_H
// 电器
class IElectricalEquipment
{
public:
virtual ~IElectricalEquipment() {}
// 打开
virtual void PowerOn() = 0;
// 关闭
virtual void PowerOff() = 0;
};
#endif // IMPLEMENTOR_H
concrete implementor
#ifndef CONCRETE_IMPLEMENTOR_H
#define CONCRETE_IMPLEMENTOR_H
#include "implementor.h"
#include <iostream>
// 电灯
class Light : public IElectricalEquipment
{
public:
// 开灯
virtual void PowerOn() override {
std::cout << "Light is on." << std::endl;
}
// 关灯
virtual void PowerOff() override {
std::cout << "Light is off." << std::endl;
}
};
// 风扇
class Fan : public IElectricalEquipment
{
public:
// 打开风扇
virtual void PowerOn() override {
std::cout << "Fan is on." << std::endl;
}
// 关闭风扇
virtual void PowerOff() override {
std::cout << "Fan is off." << std::endl;
}
};
#endif // CONCRETE_IMPLEMENTOR_H
3) 优缺点
优点:
- 不想使用继承或者因多重继承导致类的个数极具增加,可以使用桥接模式
- 一个系统存在多个(≥ 2)独立变化的维度,且这多个维度都需要独立进行扩展。
- 程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合
缺点: - 桥接模式要求正确识别出系统中两个独立变化的维度,需要经验
7. Adapter模式
1)结构图
此模式将一个类的接口转换成客户希望的接口,使原本不兼容的系统可以一起工作。
我们在应用程序中已经设计好了接口,与这个第三方提供的接口不一致,为了使得这些接口不兼容的类(不能在一起工作)可以在一起工作了,Adapter模式提供了将一个类(第三方库)的接口转化为客户(购买使用者)希望的接口。
其中Target为目标接口,即我们期望得到的接口
Adaptee:需要适配的接口
Adapter:适配器,将Adaptee包装为Target
在Adapter模式的结构图中可以看到,类模式的Adapter采用继承的方式复用Adaptee的接口,而在对象模式的Adapter中我们则采用组合的方式实现Adaptee的复用。
2)实例
Target,目标接口,俄罗斯提供的插座
#ifndef TARGET_H
#define TARGET_H
#include <iostream>
// 俄罗斯提供的插座
class IRussiaSocket
{
public:
// 使用双脚圆形充电
virtual void Charge() = 0;
};
#endif // TARGET_H
adaptee:自带的充电器
#ifndef ADAPTEE_H
#define ADAPTEE_H
#include <iostream>
using namespace std;
// 自带的充电器 - 两脚扁型
class OwnCharger
{
public:
void ChargeWithFeetFlat() {
cout << "OwnCharger::chargeWithFeetFlat" << endl;
}
};
#endif // ADAPTEE_H
转接头:
#ifndef ADAPTER_H
#define ADAPTER_H
#include "target.h"
#include "adaptee.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif
// 电源适配器
class PowerAdapter : public IRussiaSocket
{
public:
PowerAdapter(OwnCharger* pCharge) : m_pCharger(pCharge){}
~PowerAdapter() {
SAFE_DELETE(m_pCharger);
}
void Charge() { //target函数接口
// 使用自带的充电器(两脚扁型)充电
m_pCharger->ChargeWithFeetFlat(); //调用adaptee的接口,这样就实现了接口适配
}
private:
OwnCharger *m_pCharger; // 持有需要被适配的接口对象 - 自带的充电器
};
#endif // ADAPTER_H
Client
#include "adapter.h"
int main()
{
unique_ptr<OwnCharger> pAdaptee(new OwnCharger);
// 创建适配器
IRussiaSocket *pAdapter = new PowerAdapter(pAdaptee.get()); //IRussiaSocket target指针; PowerAdapter适配器
// 充电
pAdapter->Charge();
SAFE_DELETE(pAdapter);
getchar();
return 0;
}