C++之23种经典设计模式(一)
- C++之23种经典设计模式(一)
-
- 单例模式(Singleton)
- 原型模式(Prototype)
- 工厂模式(Factory)
C++之23种经典设计模式(一)
在偶然的机会里,还是决定整理一下有关程序中最为经典的GOF23种设计模式,方便以后自己查阅,此博客在于整理,下面是我参考的链接:https://blog.csdn.net/nsjim/article/details/92713881
单例模式(Singleton)
定义:
指一个类只有一个实例,且该类能自行创建这个实例的一种模式。
特点
单例模式有 3 个特点:
单例类只有一个实例对象;
该单例对象必须由单例类自行创建,其构造函数是私有的;
单例类对外提供一个访问该单例的全局访问点;
代码示例:
懒汉式单例模式:
懒汉式的特点是延迟加载,比如配置文件,采用懒汉式的方法,顾名思义,懒汉么,很懒的,配置文件的实例直到用到的时候才会加载。。。。。。
class CSingleton
{
public:
static CSingleton* GetInstance()
{
if ( m_pInstance == NULL )
m_pInstance = new CSingleton();
return m_pInstance;
}
private:
CSingleton(){};
static CSingleton * m_pInstance;
class CGarbo //它的唯一工作就是在析构函数中删除CSingleton的实例
{
public:
~CGarbo()
{
if(CSingleton::m_pInstance)
delete CSingleton::m_pInstance;
}
};
static CGarbo Garbo; //定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数
};
饿汉式:
饿汉式的特点是一开始就加载了,如果说懒汉式是“时间换空间”,那么饿汉式就是“空间换时间”,因为一开始就创建了实例,所以每次用到的之后直接返回就好了。
#include "pch.h"
#include "iostream"
using namespace std;
class CSingleton
{
public:
static CSingleton& GetInstance();
protected:
CSingleton();
~CSingleton();
private:
static CSingleton _instance;
private:
//CLock m_lkMsBsGPSInfoStartFlag;
bool m_bMsBsGPSInfoStartFlag; //
public:
bool GetMsBsGPSInfoStart();
bool SetMsBsGPSInfoStart(bool bIsStart);
};
CSingleton CSingleton::_instance;
CSingleton::CSingleton() : m_bMsBsGPSInfoStartFlag(false)
{
std::cout << "enter CSingleton::CSingleton() " << endl;
}
CSingleton::~CSingleton()
{
std::cout << "enter CSingleton::~CSingleton() " << endl;
}
CSingleton& CSingleton::GetInstance()
{
std::cout << "CSingleton::GetInstance()" << endl;
return _instance;
}
bool CSingleton::SetMsBsGPSInfoStart(bool bIsStart)
{
m_bMsBsGPSInfoStartFlag = bIsStart;
return true;
}
int main()
{
return 0;
}
};
程序输出结果:
上述代码没有调用GetInstance,但是也调用了构造跟析构函数,因为单例中的_instance是
static CSingleton _instance;
在执行以下代码的时候,会去调用它的构造函数,这就是饿汉单例的模式,在你还没使用的时候就为你创建好这个单例。
CSingleton CSingleton::_instance;
在饿汉式的单例类中,其实有两个状态,单例未初始化和单例已经初始化。假设单例还未初始化,有两个线程同时调用GetInstance方法,这时执行 m_pInstance == NULL 肯定为真,然后两个线程都初始化一个单例,最后得到的指针并不是指向同一个地方,不满足单例类的定义了,所以饿汉式的写法会出现线程安全的问题!在多线程环境下,要对其进行修改。
多线程下的单例模式
这里要处理的是懒汉模式
class Singleton
{
private:
static Singleton* m_instance;
Singleton(){}
class CGarbo //它的唯一工作就是在析构函数中删除CSingleton的实例
{
public:
~CGarbo()
{
if(CSingleton::m_pInstance)
delete CSingleton::m_pInstance;
}
};
static CGarbo Garbo; //定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数
public:
static Singleton* getInstance();
};
Singleton* Singleton::getInstance()
{
if(NULL == m_instance)
{
Lock();//借用其它类来实现,如boost
if(NULL == m_instance)
{
m_instance = new Singleton;
}
UnLock();
}
return m_instance;
}
单例模式的原文链接:
https://blog.csdn.net/zhanghuaichao/article/details/79459130
原型模式(Prototype)
定义
原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。
特点
原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。
应用场景
对象之间相同或相似,即只是个别的几个属性不同的时候。
对象的创建过程比较麻烦,但复制比较简单的时候。
想必很多人都玩过魔兽争霸3。里面有一个非常厉害的英雄叫做剑圣。这个英雄攻击力算是最高的,而且有个听起来很叼的魔法,“剑刃风暴”,这个魔法其实效果一般,不大实用。
剑圣有一个分身的功能。这个分身各个方面和剑圣都一模一样,但是没有攻击力,也没有魔法。
如何实现这个分身的功能呢?使用原型模式。原型模式就是这么一个道理,通过现有的东西,用Clone再复制拷贝出一个或者多个。
使用原型模式理由有三:
1 这个分身是游戏过程中动态生成的。剑圣使用了这个功能就动态生成分身。
2 这个分身几乎就是剑圣的拷贝。如果重新new一个剑圣不符合游戏规则。玩过War3的人都知道一个种族只能有一个剑圣吧,如果可以有3个剑圣,让其它族怎么玩。
3 重新创建一个剑圣很麻烦,要初始化各种参数,如等级啊,攻击力啊,等等各个参数,而且这些参数要和原型一致。直接通过原型模式实现则简单。
4 便于扩展。如果分身有30%原剑圣的攻击力,那么我们直接修改Clone方法即可。对外的接口不用变更。
原文链接:
https://blog.csdn.net/faithzzf/article/details/78062779
代码示例:
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string _name, int _age) :name(_name), age(_age) {}
virtual ~Person() {}
virtual void showMe()
{
cout << "I am " << name << ", and " << age << endl;
}
virtual Person *clone()
{
return new Person(*this);
}
};
class Boy :public Person
{
public:
Boy(string _name, int _age) :Person(_name, _age)
{}
~Boy() {}
virtual void showMe() override
{
Person::showMe();
cout << "I am a boy" << endl;
}
virtual Person *clone() override
{
return new Boy(*this);
}
};
class Girl :public Person
{
public:
Girl(string _name, int _age) :Person(_name, _age)
{}
~Girl() {}
virtual void showMe() override
{
Person::showMe();
cout << "I am a Girl" << endl;
}
virtual Person *clone() override
{
return new Girl(*this);
}
};
int main()
{
//创建一个boy a
Person *a = new Boy(string("Ming"), 28);
a->showMe();
//创建一个Girl b
Person *b = new Girl(string("Li"), 28);
b->showMe();
//克隆a--不使用原型模式的写法
shared_ptr<Person> cloneA(new Boy(*dynamic_cast<Boy *>(a)));
cloneA->showMe();
//克隆b--使用原型模式的写法
shared_ptr<Person> cloneB(b->clone());
cloneB->showMe();
delete b;
b = nullptr;
delete a;
a = nullptr;
delete cloneC;
return 0;
}
工厂模式(Factory)
定义
工厂方法(FactoryMethod)模式的定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。
我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背“开闭原则”。
优点
用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
缺点
每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
应用场景
客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
客户不关心创建产品的细节,只关心产品的品牌。
工厂模式也分为三种模式:
-
第一为简单工厂模式
简单工厂模式,工厂类是创建产品的,它决定创建哪一种产品,就像领导决定采用那种技术方案样。举个例子,现在有宝马车和奔驰车两种车需要生产,但是只有一个工厂,且只能在同一时间生产一种车,这时就有工厂决定生产那种车了。例子虽然不是十分恰当,但是会其意即可。我们直接看UML类图和代码吧。
代码示例:
#include <iostream>
using namespace std;
enum CarType { BENZ, BMW };
class Car//车类
{
public:
virtual void createdCar(void) = 0;
virtual ~Car() {}
};
class BenzCar : public Car //奔驰车
{
public:
BenzCar()
{
cout << "Benz::Benz()" << endl;
}
virtual void createdCar(void)
{
cout << "BenzCar::createdCar()" << endl;
}
~BenzCar()
{
cout << "BenzCar::DestroyCar" << std::endl;
}
};
class BmwCar : public Car //宝马车
{
public:
BmwCar()
{
cout << "Bmw::Bmw()" << endl;
}
virtual void createdCar(void)
{
cout << "BmwCar::createdCar()" << endl;
}
~BmwCar()
{
cout << "BmwCar::DestroyCar" << std::endl;
}
};
class CarFactory //车厂
{
public:
Car* createSpecificCar(CarType type)
{
switch (type)
{
case BENZ://生产奔驰车
return (new BenzCar());
break;
case BMW://生辰宝马车
return (new BmwCar());
break;
default:
return NULL;
break;
}
}
};
int main(int argc, char** argv)
{
CarFactory carfac;
Car* specificCarA = carfac.createSpecificCar(BENZ);//看到网上众多示例在new后没有delete,感觉不是特别严谨
Car* specificCarB = carfac.createSpecificCar(BMW);
delete specificCarA;
delete specificCarB;
return 0;
}
-
工厂方法模式
工厂方法模式:不再只由一个工厂类决定那一个产品类应当被实例化,这个决定权被交给子类去做。当有新的产品(新型汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的方法来生成即可(新车型可以用一个新类继承创建产品即可),那么就可以被客户使用,而不必去修改任何已有的代 码。可以看出工厂角色的结构也是符合开闭原则。如下面UML类图:
#include <iostream>
using namespace std;
class Car//车类
{
public:
virtual void createdCar(void) = 0;
virtual ~Car() {}
};
class BenzCar : public Car //奔驰车
{
public:
BenzCar()
{
cout << "Benz::Benz()" << endl;
}
virtual void createdCar(void)
{
cout << "BenzCar::createdCar()" << endl;
}
~BenzCar()
{
cout << "BenzCar::DestroyCar()" << endl;
}
};
class BmwCar : public Car //宝马车
{
public:
BmwCar()
{
cout << "Bmw::Bmw()" << endl;
}
virtual void createdCar(void)
{
cout << "BmwCar::createdCar()" << endl;
}
~BmwCar()
{
cout << "BmwCar::DestroyCar()" << endl;
}
};
class Factory//车厂
{
public:
virtual Car* createSpecificCar(void) = 0;
virtual ~Factory() {}
};
class BenzFactory : public Factory//奔驰车厂
{
public:
virtual Car* createSpecificCar(void)
{
return (new BenzCar());
}
~BenzFactory() { cout << "BenzFactory"; }
};
class BmwFactory : public Factory//宝马车厂
{
public:
virtual Car* createSpecificCar(void)
{
return (new BmwCar());
}
~BmwFactory() { cout << "BmwFactory"; }
};
int main(int argc, char** argv)
{
shared_ptr<Factory> factoryBenz(new BenzFactory());
Car* specificCarA = factoryBenz->createSpecificCar();
shared_ptr<Factory> factoryBmw(new BmwFactory());
Car* specificCarB = factoryBmw->createSpecificCar();
delete specificCarA;
specificCarA = nullptr;
delete specificCarB;
specificCarB = nullptr;
return 0;
}
3.抽象工厂类
在上面的工厂方法模式基础上,有需要生产高配版的奔驰和宝马,那工厂方法模式就有点鞭长莫及了,这就又有抽象工厂模式,UML类图如下:
代码如下:
#include <iostream>
using namespace std;
class Car//车类
{
public:
virtual void createdCar(void) = 0;
virtual ~Car() {}
};
class BenzCar : public Car //奔驰车
{
public:
BenzCar()
{
cout << "Benz::Benz()" << endl;
}
virtual void createdCar(void)
{
cout << "BenzCar::createdCar()" << endl;
}
~BenzCar()
{
}
};
class BmwCar : public Car //宝马车
{
public:
BmwCar()
{
cout << "Bmw::Bmw()" << endl;
}
virtual void createdCar(void)
{
cout << "BmwCar::createdCar()" << endl;
}
~BmwCar() {}
};
class HighCar //高配版车型
{
public:
virtual void createdCar(void) = 0;
virtual ~HighCar() {}
};
class HighBenzCar : public HighCar //高配奔驰车
{
public:
HighBenzCar()
{
cout << "HighBenzCarBenz::Benz()" << endl;
}
virtual void createdCar(void)
{
cout << "HighBenzCar::createdCar()" << endl;
}
~HighBenzCar() {}
};
class HighBmwCar : public HighCar //高配宝马车
{
public:
HighBmwCar()
{
cout << "HighBmwCar::Bmw()" << endl;
}
virtual void createdCar(void)
{
cout << "HighBmwCar::createdCar()" << endl;
}
~HighBmwCar() {}
};
class Factory//车厂
{
public:
virtual Car* createSpecificCar(void) = 0;
virtual HighCar* createdSpecificHighCar(void) = 0;
virtual ~Factory() {}
};
class BenzFactory : public Factory//奔驰车厂
{
public:
virtual Car* createSpecificCar(void)
{
return (new BenzCar());
}
virtual HighCar* createdSpecificHighCar(void)
{
return (new HighBenzCar());
}
~BenzFactory() {}
};
class BmwFactory : public Factory//宝马车厂
{
public:
virtual Car* createSpecificCar(void)
{
return (new BmwCar());
}
virtual HighCar* createdSpecificHighCar(void)
{
return (new HighBmwCar());
}
~BmwFactory() {}
};
int main(int argc, char** argv)
{
Factory* factory = new BenzFactory();
Car* specificCar = factory->createSpecificCar();
HighCar* spcificHighCar = factory->createdSpecificHighCar();
delete factory;
delete specificCar;
delete spcificHighCar;
return 0;
}