有個User類,其方法calculate()的內(nèi)部需要使用到外部數(shù)據(jù)類的實例中的某一個成員值作為輸入源。在User構(gòu)造函數(shù)需要傳入不同數(shù)據(jù)實例作為參數(shù),根據(jù)傳入不同的數(shù)據(jù)實例分別創(chuàng)建不同的 User 類。
先來看下A和B兩個數(shù)據(jù)類,結(jié)構(gòu)和層次不同,但是都有 Rate 這個值
struct Rate{
int value; // 被用于計算的值
};
namespace A{
struct Data{
struct Info{
int i1,i2;
Rate rate = {1};
};
Data() { info = std::make_shared<Info>();}
std::shared_ptr<Info> info;
int aa, ab, ac; //不會被User 類用到的值
};}
namespace B{
struct Data{
Rate rate = {2};
int ba, bb, bc; //不會被User 類用到的值
};}
下面是創(chuàng)建User類,傳入不同的 Data 類型構(gòu)建出不同的 User 實例
User類 example 1:
因為 User 每次只會接受一種Data類作為計算,所以可以在構(gòu)造函數(shù)中傳入 不同Data類的指針來判斷,使用指針不為空的類實例去做計算。在calculate()中,需要編寫不同的代碼來訪問 不同Data 類中的 同一個rate 值。
這個代碼看上去會非常惡心,因為根據(jù)不同的類型需要不同的代碼,如果有3~4種不同的 Data 類,calculate()就需要不同的 if 分支。
class User1
{
public:
User1(std::shared_ptr<A::Data> a, std::shared_ptr<B::Data> b){
a_ = a; b_ = b;
}
int calculate(){
int result = 0;
if (a_) {
result = a_->info->rate.value * 10;
}else if(b_){
result = b_->rate.value * 10;
}
return result;
}
std::shared_ptr<A::Data> a_;
std::shared_ptr<B::Data> b_;
};
int main()
{
User1 *u1a = new User1(std::make_shared<A::Data>(), nullptr);
u1a->calculate();
User1 *u1b = new User1(nullptr, std::make_shared<B::Data>());
u1b->calculate();
}
User類 example 2:
能不能用C++模板的方式傳入不同的 Data 呢?
思路:不管哪一種Data類,都會有 rate 這邊成員變量,只是調(diào)用的層次不一樣,那可不可以把前面的類型作為模板參數(shù)呢?
嘗試了一下,代碼如下,但是感覺還是不夠好。
template<class T=B::Data>
class User2
{
public:
User2(std::shared_ptr<T> data){
data_ = data;
}
int calculate()
{
int result = data_->rate.value * 10;
return result;
}
std::shared_ptr<T> data_;
};
int main()
{
// DataA 就傳入 A::Data::Info作為模板參數(shù)
auto u2a = new User2<A::Data::Info>(std::make_shared<A::Data::Info>());
u2a->calculate();
// DataB 就傳入 B::Data作為模板參數(shù)
auto u2b = new User2<B::Data>(std::make_shared<B::Data>());
u2b->calculate();
}
User類 example 3:
既然 User 類是需要一個 rate 值,那可不可以在構(gòu)造函數(shù)的時候傳入一個函數(shù)對象呢,在calculate()中調(diào)用這個函數(shù)對象,獲取到不同 Data 實例的 rate 值。
//把user需要的輸入值用一個函數(shù)對象傳入,user就不需要關(guān)心這個值從哪里來的了
using getRateFunc = std::function<int()>;
class User3
{
public:
User3(getRateFunc getRate)
{
getRate_ = getRate;
}
int calculate()
{
int result = getRate_() * 10;
return result;
}
getRateFunc getRate_;
};
int main()
{
//用匿名函數(shù)傳入User類需要的值
auto a = std::make_shared<A::Data>();
auto u3a = new User3([a](){
return a->info->rate.value;
});
u3a->calculate();
auto b = std::make_shared<B::Data>();
auto u3b = new User3([b]() {
return b->rate.value;
});
u3b->calculate();
}
注意的是Data類因為是純數(shù)據(jù)類,是不可以繼承接口的。
有沒有比較好的編程范式去解決這種場景下的問題呢?
另外3個例子中哪個比較可取呢?
example 3 是擴展性比較好的寫法。說擴展性好是指在增加新的 Data 類型時不要改動任何代碼。第二種模板的方式要求 Data 類型必須具有一致的結(jié)構(gòu)才可以,太脆弱了。
example 3 的問題是對使用者不友好,每次調(diào)用都要寫 lambda, 如果有大量的調(diào)用就顯得代價過高了。可以通過提取輔助函數(shù)的方式解決(或者寫成 User 類的構(gòu)造函數(shù)),每增加一個 Data 類型就對應(yīng)增加這樣一個輔助函數(shù)(或者構(gòu)造函數(shù))
當(dāng)然,以上只適合示例代碼中這種簡單邏輯。實際項目中可能復(fù)雜的多,比如要訪問十幾種 Data 類型中的十幾個成員,這時候就有必要加一個抽象層了,所有的 User 類從一個公共的接口繼承下來,每種或者每幾種 Data 類型對應(yīng)一種實現(xiàn)?;蛘甙殉橄蠼涌诜旁趦?nèi)部,User 類作為對該抽象接口調(diào)用的一個包裝類,這種方式的好處是抽象層在內(nèi)部可以隨時修改。
具體怎么做只能具體問題具體分析了。
北大青鳥APTECH成立于1999年。依托北京大學(xué)優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國IT技能型緊缺人才,是大數(shù)據(jù)專業(yè)的國家
北大青鳥中博軟件學(xué)院創(chuàng)立于2003年,作為華東區(qū)著名互聯(lián)網(wǎng)學(xué)院和江蘇省首批服務(wù)外包人才培訓(xùn)基地,中博成功培育了近30000名軟件工程師走向高薪崗位,合作企業(yè)超4
中公教育集團創(chuàng)建于1999年,經(jīng)過二十年潛心發(fā)展,已由一家北大畢業(yè)生自主創(chuàng)業(yè)的信息技術(shù)與教育服務(wù)機構(gòu),發(fā)展為教育服務(wù)業(yè)的綜合性企業(yè)集團,成為集合面授教學(xué)培訓(xùn)、網(wǎng)
達內(nèi)教育集團成立于2002年,是一家由留學(xué)海歸創(chuàng)辦的高端職業(yè)教育培訓(xùn)機構(gòu),是中國一站式人才培養(yǎng)平臺、一站式人才輸送平臺。2014年4月3日在美國成功上市,融資1
曾工作于聯(lián)想擔(dān)任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔(dān)任項目經(jīng)理從事移動互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍(lán)懿科技有限責(zé)任公司從事總經(jīng)理職務(wù)負(fù)責(zé)iOS教學(xué)及管理工作。
浪潮集團項目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺面向?qū)ο箝_發(fā)經(jīng)驗,技術(shù)功底深厚。 授課風(fēng)格 授課風(fēng)格清新自然、條理清晰、主次分明、重點難點突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫,具有快速界面開發(fā)的能力,對瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁制作和網(wǎng)頁游戲開發(fā)。
具有10 年的Java 企業(yè)應(yīng)用開發(fā)經(jīng)驗。曾經(jīng)歷任德國Software AG 技術(shù)顧問,美國Dachieve 系統(tǒng)架構(gòu)師,美國AngelEngineers Inc. 系統(tǒng)架構(gòu)師。