天天看點

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

繼續閱讀