C++之23种经典设计模式(二)
C++之23种经典设计模式(二)
在偶然的机会里,还是决定整理一下有关程序中最为经典的GOF23种设计模式,方便以后自己查阅,此博客在于整理,下面是我参考的链接:https://blog.csdn.net/nsjim/article/details/92713881
建造者模式
定义
建造者(Builder)模式的定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
优点
各个具体的建造者相互独立,有利于系统的扩展。
客户端不必知道产品内部组成的细节,便于控制细节风险。
缺点
产品的组成部分必须相同,这限制了其使用范围。
如果产品的内部变化复杂,该模式会增加很多的建造者类。
应用场景
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
UML图如下:
Director:控制者类,这是控制整个组合过程,在这个类内部有个Construct()方法,这个方法的作用就是通过调用Builder内部的各个组件的生成方法来完成组装;
Builder:构建者接口,定义各部件生成的方法;
ConcreteBuilder:具体构建者类:实现Builder构建者接口,具体定义如何生成各个部件;依赖于Product成品类,其中还有获取成品组装结构的方法GetResult()方法;
Product:成品类
代码示例:
#include <iostream>
using namespace std;
/* 产品类,这里用"电脑类"来说明 */
class Computer
{
public:
virtual void SetCPU() = 0; //CPU
virtual void SetRAM() = 0; //内存
virtual void SetDisk() = 0; //硬盘
virtual void SetCDROM() = 0;
virtual void Run() = 0;
virtual int GetRAMCount() { return m_CountOfRAM; }
virtual int GetDiskCount() { return m_CountOfDisk; }
protected:
int m_CountOfRAM; //内存条数量
int m_CountOfDisk; //硬盘数量
};
class IBMComputer : public Computer
{
public:
IBMComputer(int RAMCount, int DiskCount)
{
m_CountOfDisk = DiskCount;
m_CountOfRAM = RAMCount;
}
virtual void SetCPU()
{
printf("IBMComputer::SetCPU...\r\n");
}
virtual void SetRAM()
{
printf("IBMComputer::SetRAM...\r\n");
}
virtual void SetDisk()
{
printf("IBMComputer::SetDisk...\r\n");
}
virtual void SetCDROM()
{
printf("IBMComputer::SetCDROM...\r\n");
}
virtual void Run()
{
printf("IBMComputer::Runing...\r\n");
}
};
class LenovoComputer : public Computer
{
public:
LenovoComputer(int RAMCount, int DiskCount)
{
m_CountOfDisk = DiskCount;
m_CountOfRAM = RAMCount;
}
virtual void SetCPU()
{
printf("LenovoComputer::SetCPU...\r\n");
}
virtual void SetRAM()
{
printf("LenovoComputer::SetRAM...\r\n");
}
virtual void SetDisk()
{
printf("LenovoComputer::SetDisk...\r\n");
}
virtual void SetCDROM()
{
printf("LenovoComputer::SetCDROM...\r\n");
}
virtual void Run()
{
printf("LenovoComputer::Runing...\r\n");
}
};
class Builder
{
public:
virtual void BuildCPU() = 0;
virtual void BuildRAM() = 0;
virtual void BuildDisk() = 0;
virtual void BuildCDROM() = 0;
virtual Computer* GetComputer() = 0;
virtual ~Builder()
{
if (m_pComputer)
{
delete[]m_pComputer;
m_pComputer = NULL;
}
}
protected:
Computer* m_pComputer;
};
class IBMBuiler : public Builder
{
public:
IBMBuiler()
{
m_pComputer = new IBMComputer(2, 1);
printf("IBM 电脑,需要2个内存条,1个硬盘\r\n");
}
virtual void BuildCPU()
{
m_pComputer->SetCPU();
}
virtual void BuildRAM()
{
m_pComputer->SetRAM();
}
virtual void BuildDisk()
{
m_pComputer->SetDisk();
}
virtual void BuildCDROM()
{
m_pComputer->SetCDROM();
}
virtual Computer* GetComputer()
{
return m_pComputer;
}
};
class LenovoBuilder : public Builder
{
public:
LenovoBuilder()
{
m_pComputer = new LenovoComputer(1, 2);
printf("Lenovo 电脑,需要1个内存条,2个硬盘\r\n");
}
virtual void BuildCPU()
{
m_pComputer->SetCPU();
}
virtual void BuildRAM()
{
m_pComputer->SetRAM();
}
virtual void BuildDisk()
{
m_pComputer->SetDisk();
}
virtual void BuildCDROM()
{
m_pComputer->SetCDROM();
}
virtual Computer* GetComputer()
{
return m_pComputer;
}
};
class Director
{
public:
Director(Builder* pBuilder)
{
m_pBuilder = pBuilder;
}
void BuildComputer()
{
m_pBuilder->BuildCPU();
for (int i = 0; i < m_pBuilder->GetComputer()->GetRAMCount(); i++)
{
m_pBuilder->BuildRAM();
}
for (int i = 0; i < m_pBuilder->GetComputer()->GetDiskCount(); i++)
{
m_pBuilder->BuildDisk();
}
m_pBuilder->BuildCDROM();
}
private:
Builder* m_pBuilder;
};
void TestBuilder()
{
Builder* b1 = new IBMBuiler();
Director* director1 = new Director(b1);
director1->BuildComputer();
b1->GetComputer()->Run();
Builder* b2 = new LenovoBuilder();
Director* director2 = new Director(b2);
director2->BuildComputer();
b2->GetComputer()->Run();
delete b1;
delete b2;
delete director1;
delete director2;
}
int main()
{
TestBuilder();
return 0;
}
代理模式
定义
代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
优点
代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
代理对象可以扩展目标对象的功能;
代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
缺点
在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
增加了系统的复杂度;
UML类图:
代码如下:
#include <iostream>
#include <memory>
#include <string>
using namespace std;
/* 代理模式
* 为其他对象提供一种代理以控制对这个对象的访问,很类似装饰模式,但是这个主要的
* 是控制对对象的访问
*/
/*
* 代理模式可以分为
* 远程代理:也就是为了一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同
地址空间的事实,类似网络代理。
* 虚拟代理:是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象,
在需要时,在在代理中进行创建。
* 安全代理:用来控制真实对象访问的权限。
* 智能指引:是指当调用真实的对象时,代理处理另外一些事。
*/
class CImage
{
public:
CImage(std::string name) :m_name(name) {}
virtual ~CImage() { }
virtual void Show() = 0;
protected:
string m_name;
};
class CBigImage : public CImage
{
public:
CBigImage(std::string name) :CImage(name) {}
~CBigImage() { cout << "析构被调用" << endl; }
virtual void Show() { cout << "CBigImage Show " << m_name << endl; }
private:
};
//代理
class CBigImageProxy : public CImage
{
public:
CBigImageProxy(std::string name) :CImage(name), m_BigImage(nullptr)
{
}
virtual void Show()
{
if (nullptr == m_BigImage)
{
m_BigImage = std::make_shared<CBigImage>(this->m_name);
//m_BigImage.reset(new CBigImage(this->m_name));
}
m_BigImage->Show();
}
private:
std::shared_ptr<CBigImage> m_BigImage;
};
int main()
{
std::unique_ptr<CImage> proxy = std::make_unique<CBigImageProxy>("hello");
proxy->Show();
return 0;
}
观察者模式
定义
观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
优点
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
目标与观察者之间建立了一套触发机制。
缺点
目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
应用场景
对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
Observer 模式应该可以说是应用最多、影响最广的模式之一,因为 Observer 的一个实例 Model/View/Control( MVC) 结构在系统开发架构设计中有着很重要的地位和意义, MVC实现了业务逻辑和表示层的解耦。在 MFC 中, Doc/View(文档视图结构)提供了实现 MVC 的框架结构。在 Java 阵容中, Struts 则提供和 MFC 中 Doc/View 结构类似的实现 MVC 的框架。另外 Java 语言本身就提供了 Observer 模式的实现接口。当然, MVC 只是 Observer 模式的一个实例。 Observer 模式要解决的问题为: 建立一个一( Subject)对多( Observer) 的依赖关系, 并且做到当“一” 变化的时候, 依赖这个“一”的多也能够同步改变。
在GOF的**《设计模式:可复用面向对象软件的基础》**一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。当一个对象发生了变化,关注它的对象就会得到通知;这种交互也称为发布-订阅(publish-subscribe)。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者。
最常见的一个例子就是: 对同一组数据进行统计分析时候, 我们希望能够提供多种形式的表示 (例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据, 我们当然需要当数据改变的时候, 所有的统计的显示都能够同时改变。 Observer 模式就是解决了这一个问题。
UML类图:
代码示例:
下面代码表示,老板通知House组的人(这里就代表观察者),开会的会议室在哪。
被观察的对象接口
class ISubject;
class IObserver
{
public:
IObserver();
virtual ~IObserver() {}
virtual void Update(ISubject* Subject) = 0;
protected:
std::string meetPlace;
观察者的接口
#include <list>
#include "IObserver.h"
class ISubject
{
public:
ISubject();
virtual ~ISubject()
{
{
for (std::list<IObserver*>::iterator it = ObserverList.begin(); it != ObserverList.end(); ++it)
{
delete *it;
}
ObserverList.clear();
}
}
virtual void RegisterObserver(IObserver* Observer)=0;
virtual void RemoveObserver(IObserver* Observer) = 0;
virtual void NotifyAllObserver() = 0;
virtual void SetMeet(const std::string& str)=0;
virtual std::string GetName() const=0;
protected:
std::list<IObserver*> ObserverList;
std::string name;
};
具体的被观察者
BossSubjecr .h
#include "ISubject.h"
#include <string>
class BossSubjecr :public ISubject
{
public:
BossSubjecr();
~BossSubjecr();
virtual void NotifyAllObserver();
virtual void RegisterObserver(IObserver* Observer);
virtual void RemoveObserver(IObserver* Observer);
virtual void SetMeet(const std::string& str);
virtual std::string GetName() const;
protected:
};
老板,所有员工都需要监听老板的消息,也就是观察老板有没有发起通知,如果老板发起通知了,所有员工都要更新状态。
BossSubjecr.cpp
#include "pch.h"
#include "BossSubjecr.h"
#include <iostream>
BossSubjecr::BossSubjecr()
{
}
BossSubjecr::~BossSubjecr()
{
}
void BossSubjecr::NotifyAllObserver()
{
for (std::list<IObserver*>::iterator it = ObserverList.begin(); it != ObserverList.end(); ++it)
{
(*it)->Update(this);
}
}
void BossSubjecr::RegisterObserver(IObserver* Observer)
{
if (Observer)
{
ObserverList.push_back(Observer);
}
}
void BossSubjecr::RemoveObserver(IObserver* Observer)
{
if (Observer)
{
for (std::list<IObserver*>::iterator it = ObserverList.begin(); it != ObserverList.end(); ++it)
{
if ((*it) == Observer)
{
ObserverList.erase(it);
break;
}
}
}
}
void BossSubjecr::SetMeet(const std::string& str)
{
name = str;
std::cout<< "name:" << name << std::endl;
this->NotifyAllObserver();
}
std::string BossSubjecr::GetName() const
{
return name;
}
一个公司有多个部门,以下是隶属于House组的员工类,可以通过继承IObserver这个类去创建其他组的员工类,这里我只写了一个组,在创建这个员工类对象的时候,可以给它设计一些属性,名字、性别以及职位等等,这里我没有具体的去写。
HouseObserver .h
#include "IObserver.h"
class HouseObserver :public IObserver
{
public:
HouseObserver();
virtual void Update(ISubject* Subject);
~HouseObserver() {}
private:
};
};
#include "HouseObserver.h"
#include <iostream>
#include "ISubject.h"
HouseObserver::HouseObserver()
{
}
void HouseObserver::Update(ISubject* Subject)
{
meetPlace = Subject->GetName();
std::cout << "House组的人 收到通知,开会地点为:" << meetPlace << std::endl;
}
int main()
{
ISubject* bossSubjecr=new BossSubjecr();
for (int i = 0; i < 4; ++i)
{
IObserver* house = new HouseObserver();
bossSubjecr->RegisterObserver(house);//注册到被观察的目标类里,
}
bossSubjecr->SetMeet("信达会议室");//老板发起通知,告诉所有人,要开会了,地点是信达会议室。
//...程序结束,做一些删除对象的操作
delete bossSubjecr;
bossSubjecr = nullptr;
return 0;
}
程序执行结果: