?? 自從畢業(yè)后就沒有再寫過東西拢锹,原先的博客地址也被CSDN給封禁了舆绎,可惜了我當(dāng)年寫的研究生畢業(yè)致謝胞锰,那絕對是浩瀚致謝中的一股清流~~。言歸正傳葬凳,昨天閑暇時間瀏覽了坐在我旁邊胖子的一本書(被他看到估計會揍我一頓绰垂,畢竟我現(xiàn)在還沒他那樣的噸位~~)其中講到了traits。最近在開發(fā)一新功能的時候也碰巧使用到尤其在測試代碼中火焰,于是心血來潮準(zhǔn)備寫些東西劲装。
??traits最早是由Nathan Myers提出:Traits class: A class used in place of template parameters. As a class, it aggregates useful types and constants; as a template, it provides an avenue for that "extra level of indirection" that solves all software problems (Traits class:一種被用來取代 template parameters 的 class。作為一個 class,它聚合了有用的類型和常數(shù);作為一個 template,它為解決所有軟件提供了一條康莊大道)【摘自C++ template】昌简。
?? 對于上述評價可能有人會認(rèn)為有些夸大占业,不過當(dāng)你看過STL的源代碼后你就不會有這種想法(后面有時間會對traits在STL中的應(yīng)用詳細(xì)介紹)。平時開發(fā)過程中最讓人頭疼的就是標(biāo)記江场、開關(guān)纺酸,這類隨處改變流程處理方式的devil。為了保持代碼的整潔址否、可讀性就必須提供其他可替代的方式餐蔬,個人認(rèn)為traits算是其中之一碎紊。
下面我們使用最近參加過的一個技術(shù)認(rèn)證的題目做一下展示。
具體題目可以參考:報數(shù)游戲-實戰(zhàn)簡單設(shè)計樊诺。
??題目本身不存在什么難度仗考,難度在于變化。各種變化可能會導(dǎo)致你的代碼需要重寫词爬,碰巧當(dāng)時也使用了traits秃嗜,所以就使用該題對其進(jìn)行闡述。
1顿膨,抽取規(guī)則
實現(xiàn)過程中將不同的規(guī)則進(jìn)行分離锅锨,方便我們對規(guī)則進(jìn)行組合(在此只展示當(dāng)時的設(shè)計框架不討論實現(xiàn)細(xì)節(jié))。
規(guī)則1:
template<typename ReportTraits>
struct Rule1
{
typedef ReportTraits traits;
bool operator()(int inputNum, Result & result)
{
return isMatchRule(inputNum,result);
}
private:
bool isMatchRule(int inputNum, Result & result)
{
... ...
}
};
規(guī)則2:
template<typename ReportTraits>
struct Rule2
{
typedef ReportTraits traits;
bool operator()(int inputNum, Result & result)
{
return isMatchRule(inputNum,result);
}
private:
bool isMatchRule(int inputNum, Result & result)
{
... ...
}
};
上述規(guī)則的定義很簡單恋沃,使用“*仿函數(shù)“做接口兼容必搞,唯一的區(qū)別在于匹配過程的不同。
2囊咏、上報方式抽取
struct ReportTraits1{};
struct ReportTraits2{};
std::string doActualReport(Result &result, ReportTraits1)
{
... ...
}
std::string doActualReport(Result &result, ReportTraits2)
{
... ...
}
上述我們定義了不同的上報規(guī)則恕洲,兩個空的結(jié)構(gòu)體不帶來任何負(fù)擔(dān),目的很單純主要是為了使用traits激活重載機(jī)制梅割。
3霜第,上報框架的設(shè)計
template<typename RULE1, typename RULE2>
struct CountOff
{
std::string report(int Num)
{
Result re;
if(RULE1()(Num,re))
{
return doActualReport(re, typename RULE1::traits());
}
if(RULE2()(Num,re))
{
return doActualReport(re, typename RULE2::traits());
}
return "";
}
};
上述我們對規(guī)則進(jìn)行了組合使用,當(dāng)然如果規(guī)則較多我們可以使用變長模板户辞。調(diào)用上報接口時我們使用了各自規(guī)則的特性激活重載機(jī)制泌类,沒有過多的條件判斷。這樣就顯得很簡潔5琢恰D┦摹!
4书蚪,使用方式
CountOff<Rule1<ReportTraits1>, Rule2<ReportTraits2> >().report(2);
??以上實現(xiàn)通過仿函數(shù)進(jìn)行規(guī)則接口適配,通過每種規(guī)則所持有的traits迅栅,在利用重載機(jī)制進(jìn)行上報方式的匹配殊校,從而實現(xiàn)靈活的規(guī)則組合,而不需要任何的條件判斷读存。(不過這種實現(xiàn)現(xiàn)場好像反響不是很好~~~)为流。那么traits的具體含義是什么呢?說實話我也沒看透让簿,不過大家可以去看下《C++ template》敬察。其中將traits又區(qū)分為:traits和policy。 traits個人理解為不含動作的特性尔当,policy是有動作莲祸。
??很多人可能會質(zhì)疑說上述方式通過多態(tài)也能實現(xiàn)蹂安,確實當(dāng)時現(xiàn)場大部分人也是這樣實現(xiàn)的,不過運行效率如何呢锐帜?有人就把traits的這種方式稱為靜態(tài)多態(tài)田盈,也就是在編譯期就已經(jīng)確定的實現(xiàn)而動態(tài)多態(tài)則不然。唯一的劣勢在于模板的傳染性缴阎,不過.tcc的使用不就是為了解決這個問題么允瞧?所以哪種方式更好這個大家仁者見人吧。
??上述只是通過簡單的例子蛮拔,展示了traits的基本使用還沒有涉及特性的萃取述暂,也就是說其威力還沒有真實的展示,后面會再次通過STL對其進(jìn)行闡述建炫∑杈拢總之traits是一個很強大的編程技巧。