定義: 單來源調用指一個類的生成工作只能由特定類來執行。 eg李寧牌鞋子只能由李寧專賣店生產 這個問題歸結起來,也就是說在工廠模式中,指定的產品類只能通過具體的特定工廠類來生成,而不能自己new出來或者通過其他類生成。 具體的,我們就在代碼實現中進行說明瞭。 這裡我們來一步一步分析。 首先,一個類實 ...
定義:
單來源調用指一個類的生成工作只能由特定類來執行。
eg李寧牌鞋子只能由李寧專賣店生產
這個問題歸結起來,也就是說在工廠模式中,指定的產品類只能通過具體的特定工廠類來生成,而不能自己new出來或者通過其他類生成。
具體的,我們就在代碼實現中進行說明瞭。
這裡我們來一步一步分析。
首先,一個類實例(對象)不能自己產生,那麼。我們就需要屏蔽構造函數了。
那麼,屏蔽了構造函數之後,如何獲取一個實例呢。
有兩種方案可以實現。
方案一:
通過繼承獲取構造函數執行許可權。如代碼
class base
{
protected:
base()
{
Trace("");
}
};
class driver:protected base
{
public:
void test()
{
base b;
}
};
int main(int argc, char const *argv[])
{
driver d;
d.test();
return 0;
}
這個方案只是可以讓一個類能夠產生實例。單他和我們的意圖嚴重偏離:
a實例和子類的生命周期一致。
b沒有自主權。
c其他類也可以模擬他的實現,繼承父類獲取生成權,這顯然是個垃圾方案。
方案二:類似單例模式方法處理
產品類 構造函數屏蔽,但是提供一個獲取實例的共有方法
靜態方法獲取實例
class base
{
protected:
base()
{
Trace("");
}
public:
static base* getInstance();
};
base* base::getInstance()
{
return new base();
}
int main(int argc, char const *argv[])
{
// base* p = new base();
base * p = base::getInstance();
return 0;
}
通過方案二,我們實現了一個類不能自己執行 base *p = new base()
類型綁定
那麼下麵我們的目標就是將這個產品類和具體可生產者進行綁定了。
如何綁定呢,對於一個特定的類,處理之,我們就想到了this指針
所以我們要做的就是,產品類構造函數依賴工廠類的this 指針
// 通過靜態方法獲取,且依賴driver的this指針。
// 但是此時也可以通過臨時對象driver生成
class driver;
class base
{
protected:
base()//driver*)
{
Trace("");
}
public:
static base* getInstance(driver*);
};
base* base::getInstance(driver*)
{
return new base();
}
class driver
{
public:
base* getInstance()
{
return base::getInstance(this);
}
};
int main(int argc, char const *argv[])
{
base * p = (driver()).getInstance(); //我們所期望的運行方式。
p = base::getInstance(new driver()); //產品類抓住漏洞強行生成自我
return 0;
}
到這裡,貌似我們的目標已經達到了,但是呢。如例子中的 p = base::getInstance(new driver());這個方法,本質還是base類自主生成的。
並不能符合我們的要求。
那麼到這裡,我們應該如何處理呢。
我能想到的就是,不光讓base建立依賴driver的this指針,同時設置許可權。才能執行getinstace()
首先給出最終代碼了
// 抽象介面類,提供子類行為,同時定義許可權值以及許可權判斷給base中的getinstace方法使用
class abstractDriver
{
protected:
bool _canCreate;
abstractDriver(bool can)
:_canCreate(can)
{}
public:
virtual bool canCreate(){
return _canCreate;
}
};
class base
{
protected:
base()
{
Trace("");
}
public:
static base* getInstance(abstractDriver*);
};
// 根據依賴的this對應類是否有許可權執行決定生成
base* base::getInstance(abstractDriver*dr)
{
if (dr->canCreate())
/* code */
return new base();
else
return NULL;
}
class driver:public abstractDriver
{
public:
driver()
:abstractDriver(false)
{
Trace("");
}
//在獲取base實例前後修改許可權。保證外部許可權始終偽假
base* getInstance()
{
_canCreate = true;
base* p =base::getInstance(this);
_canCreate = false;
return p;
}
};
int main(int argc, char const *argv[])
{
base* p = base::getInstance(new driver());
cout << p <<endl; //NULL,未生成實例
p = (driver()).getInstance();
cout << p <<endl;
p = (driver()).getInstance();
cout << p <<endl;
return 0;
}
好了,最終的實現版本就完成了。
符合我們的目標
base類只能通過driver類生成。
最後,我們可以發現,這個實現中的getInstace方法讓我們想到了單例模式的實現。
不同的是單例模式的結果是最終
a只有一個類型實例產生,
b生成方式可以是自主的 base::getinstance()
而我們的單來源調用,
a。生成實例個數不一定是一個,只是生成方式限定了
b。不能通過直接調用base::getinstance()生成。
之所以拿出來將兩個模式進行比較,是因為:單來源調用並不是23種設計模式中的一種,初次看他時,我自己也是一臉矇蔽。其次,兩者都是很重要,很常用的方法。
個人源碼實現github地址:https://github.com/langya0/design_pattern_study/tree/master/singleCall
23種設計模式C++實現及擴展代碼:https://github.com/langya0/design_pattern_study
參考《Single Call 模式》