天天看点

C++之23种经典设计模式(一)C++之23种经典设计模式(一)

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;
}
};    
           

程序输出结果:

C++之23种经典设计模式(一)C++之23种经典设计模式(一)

上述代码没有调用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 电视工厂、海信电视工厂等。

创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。

客户不关心创建产品的细节,只关心产品的品牌。

工厂模式也分为三种模式:

  1. 第一为简单工厂模式

    简单工厂模式,工厂类是创建产品的,它决定创建哪一种产品,就像领导决定采用那种技术方案样。举个例子,现在有宝马车和奔驰车两种车需要生产,但是只有一个工厂,且只能在同一时间生产一种车,这时就有工厂决定生产那种车了。例子虽然不是十分恰当,但是会其意即可。我们直接看UML类图和代码吧。

    C++之23种经典设计模式(一)C++之23种经典设计模式(一)
    代码示例:
#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;
}
           
  1. 工厂方法模式

     工厂方法模式:不再只由一个工厂类决定那一个产品类应当被实例化,这个决定权被交给子类去做。当有新的产品(新型汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的方法来生成即可(新车型可以用一个新类继承创建产品即可),那么就可以被客户使用,而不必去修改任何已有的代 码。可以看出工厂角色的结构也是符合开闭原则。如下面UML类图:

     

    C++之23种经典设计模式(一)C++之23种经典设计模式(一)
    代码示例:
#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类图如下:

C++之23种经典设计模式(一)C++之23种经典设计模式(一)

代码如下:

#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;
}
           

继续阅读