單例模式(singleton)
保證一個類只有一個實例存在,提供對該實例加以訪問的全局訪問方法
實現:
- 構造函數私有化
防止別的地方調用 - 提供一個全局的靜態方法
- 類中有一個靜態指針,指向該類類型
讓類負責保存他唯一的實例。
這里隱含的含義是,程序知道這個類只能被這樣實例化。
代碼
// ./Singleton.h
class Singleton
{
private:
Singleton()=default;
static Singleton *_instance;
public:
static Singleton *instance();
static bool freeInstance();
}
// ./Singleton.cc
#include "Singleton.h"
//惰性模式,不訪問不創建,在第一次訪問的時候創建
//對靜態變量的初始化必需放在類的外部
Singleton Singleton::*_instance=nullptr;
Singleton Singleton::*instance()
{
if(_instance=nullptr)
{
_instance = new Singleton();
}
return _instance;
}
//
//非惰性模式
//在程序一運行就進行了初始化
Singleton Singleton::*_instance=new Singleton();
Singleton Singleton::*instance()
{
return _instance;
}
//
bool Singleton::freeInstance()
{
if(_instance!=nullptr)
{
delete _instance;
_instance=nullptr;
}
}
使用
#include "Singleton.h"
int main()
{
Singleton *p=Singleton::instance();
//....
return 0;
}
單例模式與多線程
惰性單例模式由于其實例初始化的方式,會導致在多線程中可能創建多個實例,所以其構造函數不是一種線程安全的函數。
因此如果使用惰性模式,需要使用互斥量。
"單例"模式
單例模式的類,可以不止有一個實例,如果一個類需要幾個特定類型,或者需要的某種類型的實例的數量只需要一個。
那么可以不使用_instance
存儲,改為map<string,Singleton*>
即可。
建造者模式
對象的構建太復雜
將對象的表示與構建分離
例如,有一些類在創建的時候,需要傳大量的參數,還可能某一下參數是選填的。
并且還可能,這個類的實例創建出來以后,還有一些字段需要填。
那么如果只是用構造函數,那么這個邏輯,這個構造函數,可能會很臃腫。
也有一些字段可能就那么幾種,也就是說有那么一個模板。
啥?你說怎么可能有這樣的類?
人員管理啊,名字,地址,聯系方式,這些是必填的選項吧。郵箱,老婆,女朋友,這些事選填的吧。萬一以后又要加上工資這個字段,咋辦?還是用構造函數?
不現實啊。
設計模式是將問題的解決方法標準化的方法,再加上解耦,這個本來就復雜的問題,變得更加復雜了。嗯~~
UML
代碼
//人員
class ClerkDetail
{
public:
clerkDetail()=default;
clerkDetail(string name); //表示必填的字段
string sex(); //下面的是字段的設置和獲取選項,使用了重載。
void sex(string s);
int age();
void age(int i);
private:
string _name;
string _sex; //下面兩個表示選填的字段
int _age;
};
//模板繼承的基類
class abClerkTplt
{
virtual void sex(); //這兩個是抽象的借口,t他們沒有參數
virtual void age(); //因為其子類,將根據子類所指示的那種模板設置參數。
virtual ClerkDetail* getclerk();
};
//人員的一些模板
class ManClerk:pubilc:abClerkTplt
{
public:
ManClerk()
{
_clerk=new ClerkDetail;
}
virtual void sex()
{
_clerk->set("man");
}
virtual void age()
{
_clerk->age(17);
}
virtual ClerkDetail* getclerk()
{
return _clerk;
}
private:
ClerkDetail *_clerk;
};
//人員的一些模板,這里還是一個模板
class WomanClerk:pubilc:abClerkTplt
{
//....
};
//一個執行模板子類的類。
class createClerk
{
public:
createClerk(abClerkTplt* Tplt)
{
_tplt=tplt;
}
vodi create()
{
tplt->age();
tplt->sex();
}
private:
abClerkTplt* _tplt;
};
//使用
int main()
{
abClerkTplt* manTplt=new ManClerk;
createClerk dir(manTplt);
dir.crete();
ClerkDetail *clerk1=manTplt->getClerk();
}
這個模式過于復雜。應該是可以簡化的吧。比如createClerk
這個類,應該可以去掉吧。
以后再想想。
原型模式
類能夠提供一個能夠復制自身的接口
復制自身則涉及到深拷貝和淺拷貝。
在復制指針類型時,如果之復制指針那么就是淺拷貝:兩個指針指向相同的地址,容易造成二次釋放。(多次釋放同一塊內存的地址)
復制指針的時候,復制指針復制地址的內容,在內存中開辟新的內存空間,而不是復制指針內容,稱為深拷貝:沒啥問題。
淺拷貝好比復制頂層。而深拷貝復制底層。
原型模式時,類自身提供一個clone()
接口,返回自身類型的指針。就這么簡單
復制的時候,要么使用默認構造函數,創建一個臨時對象,要么使用拷貝構造函數。
UML
代碼
class AbPerson
{
public:
virtual AbPerson *clone()=0;
}
class Clerk:public:AbPerson
{
public:
Clerk();
Clerk(&clerk c)
{
//這里可以直接復制的就直接復制
i=this.i;
//c因為是個指針。不能夠直接復制,需要分配內存。
c=this.cloneC();
}
virtual AbPerson *clone()
{
//轉發給拷貝構造函數,讓拷貝構造函數干活
return new Clerk(*this)
}
private:
int i;
char *c;
char *cloneC()//這里可以放一個函數,用來復制C,有幾個指針,就有幾個這種函數。
{
}
}
這一部分回頭看看書。。。深拷貝+拷貝構造函數有點蒙了。
既然有了拷貝構造函數,那么為什么還需要原型模式?
拷貝構造函數只能復制自身。
而原型模式的基類提供了一種可以復制自身的方法,并且返回基類的指針。
拷貝構造函數為原型模式提供了實現。
享元模式
使用共享對象可有效的支持大量細粒度的對象
享元模式:共享不變的那部分元素。
如果系統需要創建大量的元素,而這些元素某一部分特征又是相同的,另一部分與有自己的特征。
比如,別人都提到的文本編輯器,每個字符可共享的部分就是字符本身,特征部分是字符的字號,顏色。
比如黑白棋,棋子可共享,但是有黑白和位置之分。
享元模式將一個對象劃分為可變部分和不可變部分,該類型對象的數量并沒介紹反而增加了。但是系統中總的對象數量確實是減少了。程序所占內存減少。