保证一个类只有一个实例,并提供一个该例的全局访问点。
代码
class Singleton{
public:
static Singleton* getInstance(){
if(_pInstance == nullptr){
_pInstance = new Singleton();
}
return _pInstance;
}
private:
Singleton();
Singleton(const Singleton& clone);
Singleton& operator=(const Singleton &);
private:
static Singleton* _pInstance;
};
/*存在的问题1.资源的回收问题
*2.线程安全问题
class Singleton{
public:
static Singleton* getInstance(){
if(_pInstance == nullptr){
_pInstance = new Singleton();
atexit(Destructor());//进程退出的时候会执行
}
return _pInstance;
}
private:
static void Destructor(){
if(nullptr != _pInstance){
delete _pInstance;
_pInstance = nullptr;
}
}
Singleton();
Singleton(const Singleton& clone);
Singleton& operator=(const Singleton &);
private:
static Singleton* _pInstance;
};
/*资源回收的解决办法:1.用atexit()函数回收
2.智能指针托管,用栈的生命周期
3.内部类,也是利用的栈上对象的生命周期
class Singleton{
public:
static Singleton* getInstance(){
//std::lock_guard lock(std::mutex);粒度太大,存在隐患
if(_pInstance == nullptr){
std::lock_guard<std::mutex> lock(std::mutex);
if(_pInstance == nullptr){
_pInstance = new Singleton();
atexit(Destructor());
}
}
return _pInstance;
}
private:
static void Destructor(){
if(nullptr != _pInstance){
delete _pInstance;
_pInstance = nullptr;
}
}
Singleton();
Singleton(const Singleton& clone);
Singleton& operator=(const Singleton &);
private:
static Singleton* _pInstance;
std::mutex _mutex;
};
Singleton* Singleton::_pInstance = nullptr;
std::mutex Singlenton::_mutex;
/*解决线程安全问题:1.加锁
2.pthread_once();只执行一次
```
```c++
#include
#include
class Singleton {
public:
static Singleton * GetInstance() {
Singleton* tmp = _instance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);//获取内存屏障
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(_mutex);
tmp = _instance.load(std::memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton;
std::atomic_thread_fence(std::memory_order_release);//释放内存屏
障
_instance.store(tmp, std::memory_order_relaxed);
atexit(Destructor);
}
}
return tmp;
}
private:
static void Destructor() {
Singleton* tmp = _instance.load(std::memory_order_relaxed);
if (nullptr != tmp) {
delete tmp;
}
}
Singleton(){}
Singleton(const Singleton&) {}
Singleton& operator=(const Singleton&) {}
static std::atomic<Singleton*> _instance;
static std::mutex _mutex;
};
std::atomic<Singleton*> Singleton::_instance;//静态成员需要初始化
std::mutex Singleton::_mutex; //互斥锁初始化
// g++ Singleton.cpp -o singleton -std=c++11
//使用内存屏障保证该代码的一次性
```
版本5
//C++11 magic static 特性:如果当变量在初始化的时候,并发同时进⼊声明语句,并发
//线程将会阻塞等待初始化结束。
class Singleton{
public:
static Singleton& getInstance(){
static Singleton _Instance;
return _Instance;
}
private:
Singleton();
Singleton(const Singleton& clone);
Singleton& operator=(const Singleton &);
};
// 继承 Singleton
// g++ Singleton.cpp -o singleton -std=c++11
/*该版本具备 版本5 所有优点:
1. 利⽤静态局部变量特性,延迟加载;
2. 利⽤静态局部变量特性,系统⾃动回收内存,⾃动调⽤析构函数;
3. 静态局部变量初始化时,没有 new 操作带来的cpu指令reorder操作;
4. c++11 静态局部变量初始化时,具备线程安全;
*/
版本6
template<typename T>
class Singleton{
public:
static T & getInstance(){
static T _Instance; // 这⾥要初始化DesignPattern,需要调⽤DesignPattern 构造函数,同时会调⽤⽗类的构造函数。
return _Instance;
}
protected:
virtual ~Singleton();
Singleton();// protected修饰构造函数,才能让别⼈继承
Singleton(const T & clone);
Singleton& operator=(const T &);
};
class DessignPattern
:public Singleton<DessignPattern>
{
friend class Singleton<DessignPattern>; // friend 能让 Singleton 访问到DesignPattern构造函数
private:
DessignPattern();
DessignPattern(const DessignPattern& );
DessignPattern& operator=(const DessignPattern& );
}
结构图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mqr3M3fn-1639731122519)(C:\Users\HASEE\AppData\Roaming\Typora\typora-user-images\image-20211217150307758.png)]
定义
定义一系列算法,把它们一个个封装起来,并且使他们可以互相替换,该模式使得算法可以独立于使用它的客户程序而变化
背景
某商场节假⽇有固定促销活动,为了加⼤促销⼒度,现提升国庆节促销活动规格;
代码
//原版代码
enum VacationEnum{
VAC_Spring,
VAC_Qixi,
VAC_Duoqing
//...
};
class Promotion{
VacationEnum _vac;
public:
double CalcPromotion(){
if (vac == VAC_Spring){
// 春节
}
else if (vac == VAC_QiXi){
// 七夕
}
else if (vac == VAC_Wuyi){
// 五一
}
else if (vac == VAC_GuoQing){
// 国庆
}
}
};
//----------------------------------------------------------------------------
enum Context{
VAC_Spring,
VAC_Qixi,
VAC_Duoqing
//...
};
class ProStategy{
public:
virtual double CalcPro(const Context& ctx) = 0;
virtual ~ProStategy();
};
class VAC_Spring : public ProStategy {
public:
virtual double CalcPro(const Context &ctx){}
};
class VAC_QiXi : public ProStategy {
public:
virtual double CalcPro(const Context &ctx){}
};
class VAC_Wuyi : public ProStategy {
public:
virtual double CalcPro(const Context &ctx){}
};
class VAC_GuoQing : public ProStategy {
public:
virtual double CalcPro(const Context &ctx){}
};
class VAC_Shengdan : public ProStategy {
public:
virtual double CalcPro(const Context &ctx){}
};
//稳定点:节日对价格都要优惠 变化点:不同节日的优惠力度
class Promotion{
public:
double CalcPromotion(ProStategy* sss)
:_s(sss)
{
}
~Promotion();
double CalcPromotion(const Context& ctx){
_s->CalcPro(ctx);
}
private:
ProStategy* _s;
};
int main(){
Context ctx;
ProStategy *s = new VAC_Spring();
Promotion p(s);
p.CalcPromotion(ctx);
return;
}
要点
策略模式提供了⼀系列可重⽤的算法,从⽽可以使得类型在运⾏时⽅便地根据需要在各个算法
之间进⾏切换;策略模式消除了条件判断语句;就是在解耦合;充分体现了开闭原则;单⼀职责;
本质
分离算法,选择实现;
结构图
定义
使多个对象都有机会处理请求,从⽽避免请求的发送者和接收者之间的耦合关系。将这些对象连成⼀条链,并沿着这条链传递请求,直到有⼀个对象处理它为⽌。 ——《设计模式》GoF
背景
请假流程,1天内需要主程序批准,3天内需要项⽬经理批准,3天以上需要⽼板批准;
代码
//nginx 阶段处理
// 严格意义说是功能链
// ngx_http_init_phase_handlers 初始化责任链 cmcf->phase_engine.handlers
// ngx_http_core_run_phases 调⽤责任链**要点**
class Context{
public:
std::string name;
int day;
};
class LeaveRequest{
public:
bool HandleRequest(const Context& ctx){
//可以将具体的处理流程抽象
if(ctx.day <= 3)//判断逻辑抽象
HandleByMainProgram(ctx);
else if(ctx.day <= 10)
HandleByProjMgr(ctx);
else
HandleByBoss(ctx);
}
private:
//职责抽象
bool HandleByMainProgram(const Context &ctx) {
//...
}
bool HandleByProjMgr(const Context &ctx) {
//...
}
bool HandleByBoss(const Context &ctx) {
//...
}
};
//---------------------------------------------------------------------------
class Context{
public:
std::string name;
int day;
};
class IHandler{
public://对外提供的接口,设置链式的处理逻辑和处理的数据
virtual ~IHandler();
//责任链,往后面链起来,逻辑处理往后传递
void SetNextHandler(IHandler* next){
_next = next;
}
bool Handle(const Context* ctx){
if(CanHandle*(ctx)){//当前能处理,就返回
return HandleRequest(ctx);
}else{
return GetNextHandler()->HandleRequest(ctx);//当前不能处理,就往后传递
}
}
protected://对子类继承的接口,具体的处理,判断是否可以处理,不能处理时传递的下一级
virtual bool HandleRequest(const Context* ctx) = 0;
virtual bool CanHandle(const Context* ctx) = 0;
virtual GetNextHandler() = 0;
private:
IHandler* _next;
};
class HandleByMainProgram : public IHandler {
protected:
virtual bool HandleRequest(const Context &ctx){
//...
}
virtual bool CanHandle() {
//...
}
};
class HandleByProjMgr : public IHandler {
protected:
virtual bool HandleRequest(const Context &ctx){
//
}
virtual bool CanHandle() {
//
}
};
class HandleByBoss : public IHandler {
public:
virtual bool HandleRequest(const Context &ctx){
//
}
protected:
virtual bool CanHandle() {
//
}
};
int main(){
IHandler* p0 = new HandleByMainProgram();
IHandler* p1 = new HandleByProjMgr();
IHandler* p2 = new HandleByBoss();
p1->SetNextHandler(p0);
Context ctx;
p1->handle(ctx);
return 0;
}
要点
本质
分离职责,动态组合;
结构图
定义
动态地给⼀个对象增加⼀些额外的职责。就增加功能⽽⾔,装饰器模式⽐⽣成⼦类更为灵活。 ——《设计模式》GoF
背景
普通员⼯有销售奖⾦,累计奖⾦,部⻔经理除此之外还有团队奖⾦;后⾯可能会添加环⽐增⻓奖⾦,同时可能针对不同的职位产⽣不同的奖⾦组合;
代码
// 普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能产生不同的奖金组合;
// 销售奖金 = 当月销售额 * 4%
// 累计奖金 = 总的回款额 * 0.2%
// 部门奖金 = 团队销售额 * 1%
// 环比奖金 = (当月销售额-上月销售额) * 1%
// 销售后面的参数可能会调整
class Context {
public:
bool isMgr;
// User user;
// double groupsale;
};
class Bonus {
public:
double CalcBonus(Context &ctx) {
double bonus = 0.0;
bonus += CalcMonthBonus(ctx);
bonus += CalcSumBonus(ctx);
if (ctx.isMgr) {
bonus += CalcGroupBonus(ctx);
}
return bonus;
}
private:
double CalcMonthBonus(Context &ctx) {
double bonus/* = */;
return bonus;
}
double CalcSumBonus(Context &ctx) {
double bonus/* = */;
return bonus;
}
double CalcGroupBonus(Context &ctx) {
double bonus/* = */;
return bonus;
}
};
int main() {
Context ctx;
// 设置 ctx
Bonus *bonus = new Bonus;
bonus->CalcBonus(ctx);
}
//----------------------------------------------------------------------------
class Context {
public:
bool isMgr;
// User user;
// double groupsale;
};
// 试着从职责出发,将职责抽象出来
class CalcBonus {
public:
CalcBonus(CalcBonus * c = nullptr) {}
virtual double Calc(Context &ctx) {
return 0.0; // 基本工资
}
virtual ~CalcBonus() {}
protected:
CalcBonus* cc;
};
class CalcMonthBonus : public CalcBonus {
public:
CalcMonthBonus(CalcBonus * c) : cc(c) {}
virtual double Calc(Context &ctx) {
double mbonus /*= 计算流程忽略*/;
return mbonus + cc->Calc(ctx);
}
};
class CalcSumBonus : public CalcBonus {
public:
CalcSumBonus(CalcBonus * c) : cc(c) {}
virtual double Calc(Context &ctx) {
double sbonus /*= 计算流程忽略*/;
return sbonus + cc->Calc(ctx);
}
};
class CalcGroupBonus : public CalcBonus {
public:
CalcGroupBonus(CalcBonus * c) : cc(c) {}
virtual double Calc(Context &ctx) {
double gbnonus /*= 计算流程忽略*/;
return gbnonus + cc->Calc(ctx);
}
};
class CalcCycleBonus : public CalcBonus {
public:
CalcGroupBonus(CalcBonus * c) : cc(c) {}
virtual double Calc(Context &ctx) {
double gbnonus /*= 计算流程忽略*/;
return gbnonus + cc->Calc(ctx);
}
};
int main() {
// 1. 普通员工
Context ctx1;
CalcBonus *base = new CalcBonus();
CalcBonus *cb1 = new CalcMonthBonus(base);
CalcBonus *cb2 = new CalcSumBonus(cb1);
cb2->Calc(ctx1);
// 2. 部门经理
Context ctx2;
CalcBonus *cb3 = new CalcGroupBonus(cb2);
cb3->Calc(ctx2);
}
要点
通过采⽤组合⽽⾮继承的⼿法, 装饰器模式实现了在运⾏时动态扩展对象功能的能⼒,⽽且可以根据需要扩展多个功能。 避免了使⽤继承带来的“灵活性差”和“多⼦类衍⽣问题”。不是解决“多⼦类衍⽣的多继承”问题,⽽是解决“⽗类在多个⽅向上的扩展功能”问题;装饰器模式把⼀系列复杂的功能分散到每个装饰器当中,⼀般⼀个装饰器只实现⼀个功能,实现复⽤装饰器的功能;
本质
动态组合
结构图