保证一个类仅有一个实例,并提供一个该实例的全局访问点
可以发现C++中 ostream就有点类似这个样子,禁止了拷贝和构造函数
class Singleton{
public:
static Singleton * GetInstance(){
if(_instance == nullptr){
//线程不安全,Singleton对象可能被重复创建
_instance = new Singleton(); //在堆区开辟空间
}
return _instance;
}
private:
Singletion(){} //构造,禁止用户自己调用
~Singleton(){}
Singleton(const Singleton &clone){} //copy constructor
Singleton& operator=(const Singleton&) {}
static Singleton * _instance; //静态成员存放在全局区(global variables也是)
};
Singleton* Singleton::_instance = nullptr; // 静态成员,类内声明类外初始化
解决了没有析构对象的问题
class Singleton{
public:
static Singleton * GetInstance(){
if(_instance == nullptr){
_instance = new Singleton(); //在堆区开辟空间
atexit(Destructor); //进程终止时调用Destructor函数
}
return _instance;
}
private:
//静态成员是归属于整个类的,所以在进程退出时可以被调用
static void Destructor(){
if(nullptr != _instance)
{
delete _instance;
_instance = nullptr;
}
}
Singletion(){} //构造,禁止用户自己调用
~Singleton(){}
Singleton(const Singleton &clone){} //copy constructor
Singleton& operator=(const Singleton&) {}
static Singleton * _instance; //静态成员存放在全局区(global variables也是)
};
Singleton* Singleton::_instance = nullptr; // 静态成员,类内声明类外初始化
//还可以使用内部类 或者智能指针来解决,此时还有线程安全问题
该版本称为懒汉模式 lazy load,解决了多线程环境下可能多次new Singleton对象
class Singleton{
public:
static Singleton * GetInstance(){
//std::lock_guard lock(_mutex); 3.1切换线程
if(_instance == nullptr){
std::lock_guard<std::mutex> lock(_mutex); //3.2
if(_instance == nullptr){ //if判断防止多线程时重复new 对象
_instance = new Singleton(); //在堆区开辟空间
// new有三步操作:
//1. 分配内存
//2. 调用构造函数
//3. 返回指针
//但是在多线程环境下 有cpu reorder操作
//导致顺序为1 3 2,从而没调用构造函数,导致_instance为野指针了。
atexit(Destructor);
}
}
return _instance;
}
private:
static void Destructor(){
if(nullptr != _instance)
{
delete _instance;
_instance = nullptr;
}
}
Singletion(){} //构造,禁止用户自己调用
~Singleton(){}
Singleton(const Singleton &clone){} //copy constructor
Singleton& operator=(const Singleton&) {}
static Singleton * _instance; //静态成员存放在全局区(global variables也是)
static std::mutex _mutex; //!!!
};
Singleton* Singleton::_instance = nullptr; // 静态成员,类内声明类外初始化
std::mutex Singleton::_mutex;
如果采用3.1处加锁而注释 3.2 ,则锁“太重”,因为创建对象只有一次,而如果加在 3.1 处,则后来获取指针来读对象时也需要加锁开销太大。
该版本使用内存屏障解决CPU reorder问题
class Singleton{
public:
static Singleton * GetInstance(){
Singleton *tmp = _instance.load(std::memory_order_relaxed);//4.2
std::atomic_thread_fence(std::memory_order_acquire);//4.1 获取内存屏障
if(_instance == nullptr){
std::lock_guard<std::mutex> lock(_mutex); //
if(_instance == nullptr){ //if判断防止多线程时重复new 对象
_instance = new Singleton(); //此时new三步骤按顺序进行
std::atomic_thread_fence(std::memory_order_release);//释放内存屏障 ,与4.1对应
_instance.store(tmp, std::memory_order_relaxed);// 与4.2对应,可理解为保持原子性
atexit(Destructor);
}
}
return _instance;
}
private:
static void Destructor(){
if(nullptr != _instance)
{
delete _instance;
_instance = nullptr;
}
}
Singletion(){} //构造,禁止用户自己调用
~Singleton(){}
Singleton(const Singleton &clone){} //copy constructor
Singleton& operator=(const Singleton&) {}
static Singleton * _instance; //静态成员存放在全局区(global variables也是)
static std::mutex _mutex; //!!!
};
Singleton* Singleton::_instance = nullptr; // 静态成员,类内声明类外初始化
std::mutex Singleton::_mutex;
这里内存屏障相关知识点可自行搜索学习,这里只给出解决方案。
使用c++11 magic static特性,如果当变量在初始化时,并发线程同时进入声明语句,则会阻塞等待直到初始化结束
该方法在effective C++ 中有提及
class Singleton
{
public:
static Singleton& GetInstance(){
static Singleton instance;//存储在静态全局区
return instance;
}
private:
Singleton(){}
~Singleton(){}
Singleton(const Singleton&){}
Singleton& operator=(const Singleton&){}
};
该版本利用模板提高了复用性,使得其他类通过单例基类来实现单例模式。
template<typename T>
class Singleton
{
public:
static T& GetInstance(){
static T instance; // 这里会调用T类型(子)构造函数,和父类的构造函数
return instance;
}
private:
Singleton(){}
virtual ~Singleton(){}
Singleton(const Singleton&){}
Singleton& operator=(const Singleton&){}
};
class DesignPattern : public Singleton<DesignPattern>{
friend class Singleton<DesignPattern>; //使得父类可以调用本类的构造函数
public:
~DesignPattern(){}
private:
DesingPattern(){}
DesignPattern(const DesignPattern&){}
DesginPattern& operator=(const DesignPattern&){}
}

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。
实现一个导出数据的接口,让客户选择数据导出的方式
延迟到子类来选择实现

// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:
virtual bool Export(const std::string &data) = 0;
virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportJson : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
// csv
class ExportTxt : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
int main() {
std::string choose/* = */;
if (choose == "txt") {
/***/
IExport *e = new ExportTxt();
/***/
e->Export("hello world");
} else if (choose == "json") {
/***/
IExport *e = new ExportJson();
/***/
e->Export("hello world");
} else if (choose == "xml") {
IExport *e = new ExportXml();
e->Export("hello world");
} else if (choose == "csv") {
IExport *e = new ExportXml();
e->Export("hello world");
}
}
class IExport {
public:
virtual bool Export(const std::string &data) = 0;
virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportJson : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportTxt : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class IExportFactory {
public:
virtual IExport * NewExport(/* ... */) = 0;
};
class ExportXmlFactory : public IExportFactory {
public:
//将对象创建过程也封装起来
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportXml;
// 可能之后有什么操作
return temp;
}
};
class ExportJsonFactory : public IExportFactory {
public:
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportJson;
// 可能之后有什么操作
return temp;
}
};
class ExportTxtFactory : public IExportFactory {
public:
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportTxt;
// 可能之后有什么操作
return temp;
}
};
class ExportData {
public:
ExportData(IExportFactory *factory) : _factory(factory) {}
~ExportData() {
if (_factory) {
delete _factory;
_factory = nullptr;
}
}
bool Export(const std::string &data) { // 稳定的流程 往基类放
IExport * e = _factory->NewExport();
e->Export(data);
}
private:
IExportFactory *_factory;
};
int main() {
ExportData ed(new ExportTxtFactory);
ed.Export("hello world");
return 0;
}
class IExport {
public:
virtual bool Export(const std::string &data) = 0;
virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportJson : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportTxt : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportCSV : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
//工厂基类
class IExportFactory {
public:
IExportFactory() {
_export = nullptr;
}
virtual ~IExportFactory() {
if (_export) {
delete _export;
_export = nullptr;
}
}
//进一步的封装
bool Export(const std::string &data) {
if (_export == nullptr) {
_export = NewExport();
}
return _export->Export(data);
}
protected:
virtual IExport * NewExport(/* ... */) = 0;
private:
IExport* _export;
};
class ExportXmlFactory : public IExportFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportXml();
// 可能之后有什么操作
return temp;
}
};
class ExportJsonFactory : public IExportFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportJson;
// 可能之后有什么操作
return temp;
}
};
class ExportTxtFactory : public IExportFactory {
protected:
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportTxt;
// 可能之后有什么操作
return temp;
}
};
class ExportCSVFactory : public IExportFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportCSV;
// 可能之后有什么操作
return temp;
}
};
int main () {
IExportFactory *factory = new ExportTxtFactory();
factory->Export("hello world");
return 0;
}
工厂模式通常会结合模板模式 和 单例模式使用
工厂模式一般用于封装某些对用户无需可见的操作(如new)
提供一个接口,让该接口负责创建一系列 相关或者相互依赖的对象,无需指定它们具体的类
实现一个拥有导入导出数据的接口,让客户选择数据的导出导入方式

下面代码主要是封装相关性,而实际工作中是封装依赖性为多。
class IExport {
public:
virtual bool Export(const std::string &data) = 0;
virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportJson : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportTxt : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportCSV : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class IImport {
public:
virtual bool Import(const std::string &data) = 0;
virtual ~IImport(){}
};
class ImportXml : public IImport {
public:
virtual bool Import(const std::string &data) {
return true;
}
};
class ImportJson : public IImport {
public:
virtual bool Import(const std::string &data) {
return true;
}
};
class ImportTxt : public IImport {
public:
virtual bool Import(const std::string &data) {
return true;
}
};
// 对于初学者: 知道扩展代码
// 5年
class ImportCSV : public IImport {
public:
virtual bool Import(const std::string &data) {
// ....
return true;
}
};
//!!!关键接口类
class IDataApiFactory {
public:
IDataApiFactory() {
_export = nullptr;
_import = nullptr;
}
virtual ~IDataApiFactory() {
if (_export) {
delete _export;
_export = nullptr;
}
if (_import) {
delete _import;
_import = nullptr;
}
}
bool Export(const std::string &data) {
if (_export == nullptr) {
_export = NewExport();
}
return _export->Export(data);
}
bool Import(const std::string &data) {
if (_import == nullptr) {
_import = NewImport();
}
return _import->Import(data);
}
protected:
virtual IExport * NewExport(/* ... */) = 0;
virtual IImport * NewImport(/* ... */) = 0;
private:
IExport *_export;
IImport *_import;
};
class XmlApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportXml;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportXml;
// 可能之后有什么操作
return temp;
}
};
class JsonApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportJson;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportJson;
// 可能之后有什么操作
return temp;
}
};
class TxtApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportTxt;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportTxt;
// 可能之后有什么操作
return temp;
}
};
class CSVApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportCSV;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportCSV;
// 可能之后有什么操作
return temp;
}
};
// 相关性 依赖性 工作当中
int main () {
IDataApiFactory *factory = new CSVApiFactory();
factory->Import("hello world");
factory->Export("hello world");
return 0;
}
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
Nginx代码就是利用了责任链,它将http请求分为了11个阶段,如accept、header处理(token登录验证)、body处理.
请求流程:1天内需要主程序员批准,3天内需要项目经理批准,3天以上需要老板批准
稳定点:处理流程
变化点:请假天数,处理链条长度,谁来处理
对稳定点进行抽象,对变化点进行扩展
分离职责,动态组合

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 if (GetNextHandler()) {
return GetNextHandler()->Handle(ctx);
} else {
// err
}
return false;
}
protected:
virtual bool HandleRequest(const Context &ctx) = 0;
virtual bool CanHandle(const Context &ctx) =0;
IHandler * GetNextHandler() {
return next;
}
private:
IHandler *next; //指向下一个处理人
};
// 能不能处理,以及怎么处理
class HandleByMainProgram : public IHandler {
protected:
virtual bool HandleRequest(const Context &ctx){
//
return true;
}
virtual bool CanHandle(const Context &ctx) {
//
if (ctx.day <= 10)
return true;
return false;
}
};
class HandleByProjMgr : public IHandler {
protected:
virtual bool HandleRequest(const Context &ctx){
//
return true;
}
virtual bool CanHandle(const Context &ctx) {
//
if (ctx.day <= 20)
return true;
return false;
}
};
class HandleByBoss : public IHandler {
protected:
virtual bool HandleRequest(const Context &ctx){
//
return true;
}
virtual bool CanHandle(const Context &ctx) {
//
if (ctx.day < 30)
return true;
return false;
}
};
//秘书处理
class HandleByBeauty : public IHandler {
protected:
virtual bool HandleRequest(const Context &ctx){
//
return true;
}
virtual bool CanHandle(const Context &ctx) {
//
if (ctx.day <= 3)
return true;
return false;
}
};
int main() {
// 可以用抽象工厂优化
// nginx http 处理
IHandler * h0 = new HandleByBeauty();
IHandler * h1 = new HandleByMainProgram();
IHandler * h2 = new HandleByProjMgr();
IHandler * h3 = new HandleByBoss();
h0->SetNextHandler(h1);
h1->SetNextHandler(h2);
h2->SetNextHandler(h3);
// 设置下一指针
Context ctx;
h0->Handle(ctx);
return 0;
}
动态的给一个对象增加一些额外的职责,就增加功能来说,装饰器模式比生产子类更加灵活。
普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖
金,同时可能针对不同的职位产生不同的奖金组合;

稳定点: 增加奖金的规则
变化点:员工类型;不同奖金的组合
动态组合
class Context {
public:
bool isMgr;
// User user;
// double groupsale;
};
class CalcBonus {
public:
CalcBonus(CalcBonus * c = nullptr) : cc(c) {}
virtual double Calc(Context &ctx) {
return 0.0; // 基本工资
}
virtual ~CalcBonus() {}
protected:
CalcBonus* cc; //组合的方式
};
class CalcMonthBonus : public CalcBonus {
public:
CalcMonthBonus(CalcBonus * c) : CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double mbonus /*= 计算流程忽略*/;
return mbonus + cc->Calc(ctx);
}
};
class CalcSumBonus : public CalcBonus {
public:
CalcSumBonus(CalcBonus * c) : CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double sbonus /*= 计算流程忽略*/;
return sbonus + cc->Calc(ctx);
}
};
class CalcGroupBonus : public CalcBonus {
public:
CalcGroupBonus(CalcBonus * c) : CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double gbnonus /*= 计算流程忽略*/;
return gbnonus + cc->Calc(ctx);
}
};
class CalcCycleBonus : public CalcBonus {
public:
CalcCycleBonus(CalcBonus * c) : CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double gbnonus /*= 计算流程忽略*/;
return gbnonus + cc->Calc(ctx);
}
};
int main() {
//装饰器(decorator)这类似于是一个[功能链],要与责任链区分一下
//责任链强调顺序,且有打断功能
//装饰器与顺序无关
// 1. 普通员工
Context ctx1;
CalcBonus *base = new CalcBonus();
CalcBonus *cb2 = new CalcSumBonus(base);
CalcBonus *cb1 = new CalcMonthBonus(cb2);
cb2->Calc(ctx1); //计算只包含SumBonus的员工ctx1的奖金数
// 2. 部门经理
Context ctx2;
CalcBonus *cb3 = new CalcGroupBonus(cb2);
//计算包含所有奖金的雇员ctx2的总奖金
cb3->Calc(ctx2);
}