基本類型偏執(zhí)
基本類型偏執(zhí)(Primitive Obsession)
- 使用基本類型而不是小對象來實(shí)現(xiàn)簡單任務(wù)(例如貨幣储玫、范圍龙巨、電話號碼字符串等)辨绊。
- 使用常量編碼信息(例如一個用于引用管理員權(quán)限的常量USER_ADMIN_ROLE = 1 )扒秸。
- 使用字符串常量作為字段名在數(shù)組中使用骚露。
大多數(shù)編程語言都支持基本數(shù)據(jù)類型和結(jié)構(gòu)類型(類蕴掏、結(jié)構(gòu)體等)障般。結(jié)構(gòu)類型允許程序員將基本數(shù)據(jù)類型組織起來,以代表某一事物的模型盛杰。
基本數(shù)據(jù)類型可以看成是機(jī)構(gòu)類型的積木塊挽荡。當(dāng)基本數(shù)據(jù)類型數(shù)量成規(guī)模后,將它們有組織地結(jié)合起來即供,可以更方便的管理這些數(shù)據(jù)定拟。
- 如果你有大量的基本數(shù)據(jù)類型字段,就有可能將其中部分存在邏輯聯(lián)系的字段組織起來逗嫡,形成一個類青自。更進(jìn)一步的是株依,將與這些數(shù)據(jù)有關(guān)聯(lián)的方法也一并移入類中。為了實(shí)現(xiàn)這個目標(biāo)延窜,可以嘗試 以類取代類型碼(Replace Type Code with Class) 恋腕。
- 如果基本數(shù)據(jù)類型字段的值是用于方法的參數(shù),可以使用 引入?yún)?shù)對象(Introduce Parameter Object) 或 保持對象完整(Preserve Whole Object) 逆瑞。
- 如果想要替換的數(shù)據(jù)值是類型碼吗坚,而它并不影響行為,則可以運(yùn)用 以類取代類型碼(Replace Type Code with Class) 將它替換掉呆万。如果你有與類型碼相關(guān)的條件表達(dá)式,可運(yùn)用 以子類取代類型碼(Replace Type Code with Subclass) 或 以狀態(tài)/策略模式取代類型碼(Replace Type Code with State/Strategy) 加以處理车份。
- 如果你發(fā)現(xiàn)自己正從數(shù)組中挑選數(shù)據(jù)谋减,可運(yùn)用 以對象取代數(shù)組(Replace Array with Object) 。
收益
- 多虧了使用對象替代基本數(shù)據(jù)類型扫沼,使得代碼變得更加靈活出爹。
- 代碼變得更加易讀和更加有組織。特殊數(shù)據(jù)可以集中進(jìn)行操作缎除,而不像之前那樣分散严就。不用再猜測這些陌生的常量的意義以及它們?yōu)槭裁丛跀?shù)組中。
- 更容易發(fā)現(xiàn)重復(fù)代碼器罐。
重構(gòu)方法說明
以類取代類型碼(Replace Type Code with Class)
問題
類之中有一個數(shù)值類型碼梢为,但它并不影響類的行為。
解決
以一個新的類替換該數(shù)值類型碼轰坊。
引入?yún)?shù)對象(Introduce Parameter Object)
問題
某些參數(shù)總是很自然地同時出現(xiàn)铸董。
解決
以一個對象來取代這些參數(shù)。
保持對象完整(Preserve Whole Object)
問題
你從某個對象中取出若干值肴沫,將它們作為某一次函數(shù)調(diào)用時的參數(shù)粟害。
解決
改為傳遞整個對象。
以子類取代類型碼(Replace Type Code with Subclass)
問題
你有一個不可變的類型碼颤芬,它會影響類的行為悲幅。
解決
以子類取代這個類型碼。
以狀態(tài)/策略模式取代類型碼(Replace Type Code with State/Strategy)
問題
你有一個類型碼站蝠,它會影響類的行為汰具,但你無法通過繼承消除它。
解決
以狀態(tài)對象取代類型碼沉衣。
以對象取代數(shù)組(Replace Array with Object)
問題
你有一個數(shù)組郁副,其中的元素各自代表不同的東西。
解決
以對象替換數(shù)組豌习。對于數(shù)組中的每個元素存谎,以一個字段來表示拔疚。
數(shù)據(jù)泥團(tuán)
數(shù)據(jù)泥團(tuán)(Data Clumps)
有時,代碼的不同部分包含相同的變量組(例如用于連接到數(shù)據(jù)庫的參數(shù))既荚。這些綁在一起出現(xiàn)的數(shù)據(jù)應(yīng)該擁有自己的對象稚失。
問題原因
通常,數(shù)據(jù)泥團(tuán)的出現(xiàn)時因?yàn)樵愀獾木幊探Y(jié)構(gòu)或“復(fù)制-粘貼式編程”恰聘。
有一個判斷是否是數(shù)據(jù)泥團(tuán)的好辦法:刪掉眾多數(shù)據(jù)中的一項(xiàng)句各。這么做,其他數(shù)據(jù)有沒有因而失去意義晴叨?如果它們不再有意義凿宾,這就是個明確的信號:你應(yīng)該為它們產(chǎn)生一個新的對象。
解決方法
- 首先找出這些數(shù)據(jù)以字段形式出現(xiàn)的地方兼蕊,運(yùn)用 提煉類(Extract Class) 將它們提煉到一個獨(dú)立對象中初厚。
- 如果數(shù)據(jù)泥團(tuán)在函數(shù)的參數(shù)列中出現(xiàn),運(yùn)用 引入?yún)?shù)對象(Introduce Parameter Object) 將它們組織成一個類孙技。
- 如果數(shù)據(jù)泥團(tuán)的部分?jǐn)?shù)據(jù)出現(xiàn)在其他函數(shù)中产禾,考慮運(yùn)用 保持對象完整(Preserve Whole Object) 將整個數(shù)據(jù)對象傳入到函數(shù)中。
- 檢視一下使用這些字段的代碼牵啦,也許亚情,將它們移入一個數(shù)據(jù)類是個不錯的主意。
收益
- 提高代碼易讀性和組織性哈雏。對于特殊數(shù)據(jù)的操作楞件,可以集中進(jìn)行處理,而不像以前那樣分散僧著。
- 減少代碼量履因。
何時忽略
- 有時為了對象中的部分?jǐn)?shù)據(jù)而將整個對象作為參數(shù)傳遞給函數(shù),可能會產(chǎn)生讓兩個類之間不收歡迎的依賴關(guān)系盹愚,這中情況下可以不傳遞整個對象栅迄。
重構(gòu)方法說明
提煉類(Extract Class)
問題
某個類做了不止一件事。
解決
建立一個新類皆怕,將相關(guān)的字段和函數(shù)從舊類搬移到新類毅舆。
引入?yún)?shù)對象(Introduce Parameter Object)
問題
某些參數(shù)總是很自然地同時出現(xiàn)。
解決
以一個對象來取代這些參數(shù)愈腾。
保持對象完整(Preserve Whole Object)
問題
你從某個對象中取出若干值憋活,將它們作為某一次函數(shù)調(diào)用時的參數(shù)。
解決
改為傳遞整個對象虱黄。
過大的類
過大的類(Large Class)
一個類含有過多字段悦即、函數(shù)、代碼行。
問題原因
類通常一開始很小辜梳,但是隨著程序的增長而逐漸膨脹粱甫。
類似于過長函數(shù),程序員通常覺得在一個現(xiàn)存類中添加新特性比創(chuàng)建一個新的類要容易作瞄。
解決方法
設(shè)計模式中有一條重要原則:職責(zé)單一原則茶宵。一個類應(yīng)該只賦予它一個職責(zé)。如果它所承擔(dān)的職責(zé)太多宗挥,就該考慮為它減減負(fù)乌庶。
- 如果過大類中的部分行為可以提煉到一個獨(dú)立的組件中,可以使用 提煉類(Extract Class)契耿。
- 如果過大類中的部分行為可以用不同方式實(shí)現(xiàn)或使用于特殊場景瞒大,可以使用 提煉子類(Extract Subclass)。
- 如果有必要為客戶端提供一組操作和行為搪桂,可以使用 提煉接口(Extract Interface)糠赦。
- 如果你的過大類是個 GUI 類,可能需要把數(shù)據(jù)和行為移到一個獨(dú)立的領(lǐng)域?qū)ο笕ス亍D憧赡苄枰獌蛇吀鞅A粢恍┲貜?fù)數(shù)據(jù),并保持兩邊同步淌山。 復(fù)制被監(jiān)視數(shù)據(jù)(Duplicate Observed Data) 可以告訴你怎么做裸燎。
收益
- 重構(gòu)過大的類可以使程序員不必記住一個類中大量的屬性。
- 在大多數(shù)情況下泼疑,分割過大的類可以避免代碼和功能的重復(fù)德绿。
重構(gòu)方法說明
提煉類(Extract Class)
問題
某個類做了不止一件事。
解決
建立一個新類退渗,將相關(guān)的字段和函數(shù)從舊類搬移到新類移稳。
提煉子類(Extract Subclass)
問題
一個類中有些特性僅用于特定場景。
解決
創(chuàng)建一個子類会油,并將用于特殊場景的特性置入其中个粱。
提煉接口(Extract Interface)
問題
多個客戶端使用一個類部分相同的函數(shù)。另一個場景是兩個類中的部分函數(shù)相同翻翩。
解決
移動相同的部分函數(shù)到接口中都许。
復(fù)制被監(jiān)視數(shù)據(jù)(Duplicate Observed Data)
問題
如果存儲在類中的數(shù)據(jù)是負(fù)責(zé) GUI 的。
解決
一個比較好的方法是將負(fù)責(zé) GUI 的數(shù)據(jù)放入一個獨(dú)立的類嫂冻,以確保 GUI 數(shù)據(jù)與域類之間的連接和同步胶征。
過長函數(shù)
過長函數(shù)(Long Method)
一個函數(shù)含有太多行代碼。一般來說桨仿,任何函數(shù)超過 10 行時睛低,你就可以考慮是不是過長了。 函數(shù)中的代碼行數(shù)原則上不要超過 100 行。
問題的原因
通常情況下钱雷,創(chuàng)建一個新函數(shù)的難度要大于添加功能到一個已存在的函數(shù)骂铁。大部分人都覺得:“我就添加這么兩行代碼,為此新建一個函數(shù)實(shí)在是小題大做了急波〈硬”于是,張三加兩行澄暮,李四加兩行名段,王五加兩行。泣懊。伸辟。函數(shù)日益龐大,最終爛的像一鍋漿糊馍刮,再也沒人能完全看懂了信夫。于是大家就更不敢輕易動這個函數(shù)了,只能惡性循環(huán)的往其中添加代碼卡啰。所以静稻,如果你看到一個超過 200 行的函數(shù),通常都是多個程序員東拼西湊出來的匈辱。
解決函數(shù)
一個很好的技巧是:尋找注釋振湾。添加注釋,一般有這么幾個原因:代碼邏輯較為晦澀或復(fù)雜亡脸;這段代碼功能相對獨(dú)立押搪;特殊處理。 如果代碼前方有一行注釋浅碾,就是在提醒你:可以將這段代碼替換成一個函數(shù)大州,而且可以在注釋的基礎(chǔ)上給這個函數(shù)命名。如果函數(shù)有一個描述恰當(dāng)?shù)拿执剐唬筒恍枰タ磧?nèi)部代碼究竟是如何實(shí)現(xiàn)的厦画。就算只有一行代碼,如果它需要以注釋來說明滥朱,那也值得將它提煉到獨(dú)立函數(shù)中苛白。
- 為了給一個函數(shù)瘦身,可以使用 提煉函數(shù)(Extract Method)焚虱。
- 如果局部變量和參數(shù)干擾提煉函數(shù)购裙,可以使用 以查詢?nèi)〈R時變量(Replace Temp with Query),引入?yún)?shù)對象(Introduce Parameter Object) 或 保持對象完整(Preserve Whole Object) 鹃栽。
- 如果前面兩條沒有幫助躏率,可以通過 以函數(shù)對象取代函數(shù)(Replace Method with Method Object) 嘗試移動整個函數(shù)到一個獨(dú)立的對象中躯畴。
- 條件表達(dá)式和循環(huán)常常也是提煉的信號。對于條件表達(dá)式薇芝,可以使用 分解條件表達(dá)式(Decompose Conditional) 蓬抄。至于循環(huán),應(yīng)該使用 提煉函數(shù)(Extract Method) 將循環(huán)和其內(nèi)的代碼提煉到獨(dú)立函數(shù)中夯到。
收益
- 在所有類型的面向?qū)ο蟠a中嚷缭,函數(shù)比較短小精悍的類往往生命周期較長。一個函數(shù)越長耍贾,就越不容易理解和維護(hù)阅爽。
- 此外,過長函數(shù)中往往含有難以發(fā)現(xiàn)的重復(fù)代碼荐开。
性能
是否像許多人說的那樣付翁,增加函數(shù)的數(shù)量會影響性能?在幾乎絕大多數(shù)情況下晃听,這種影響是可以忽略不計百侧,所以不用擔(dān)心。 此外能扒,現(xiàn)在有了清晰和易讀的代碼佣渴,在需要的時候,你將更容易找到真正有效的函數(shù)來重組代碼和提高性能初斑。
重構(gòu)方法說明
提煉函數(shù)(Extract Method)
問題
你有一段代碼可以組織在一起观话。
解決
移動這段代碼到一個新的函數(shù)中,使用函數(shù)的調(diào)用來替代老代碼越平。
以查詢?nèi)〈R時變量(Replace Temp with Query)
問題
將表達(dá)式的結(jié)果放在局部變量中,然后在代碼中使用灵迫。
解決
將整個表達(dá)式移動到一個獨(dú)立的函數(shù)中并返回結(jié)果秦叛。使用查詢函數(shù)來替代使用變量。如果需要瀑粥,可以在其他函數(shù)中合并新函數(shù)挣跋。
引入?yún)?shù)對象(Introduce Parameter Object)
問題
某些參數(shù)總是很自然地同時出現(xiàn)。
解決
以一個對象來取代這些參數(shù)狞换。
保持對象完整(Preserve Whole Object)
問題
你從某個對象中取出若干值避咆,將它們作為某一次函數(shù)調(diào)用時的參數(shù)。
解決
改為傳遞整個對象修噪。
以函數(shù)對象取代函數(shù)(Replace Method with Method Object)
問題
你有一個過長函數(shù)查库,它的局部變量交織在一起,以致于你無法應(yīng)用提煉函數(shù)(Extract Method) 黄琼。
解決
將函數(shù)移到一個獨(dú)立的類中樊销,使得局部變量成了這個類的字段。然后,你可以將函數(shù)分割成這個類中的多個函數(shù)围苫。
分解條件表達(dá)式(Decompose Conditional)
問題
你有復(fù)雜的條件表達(dá)式裤园。
解決
根據(jù)條件分支將整個條件表達(dá)式分解成幾個函數(shù)。
過長參數(shù)列
過長參數(shù)列(Long Parameter List)
一個函數(shù)有超過 3剂府、4 個入?yún)ⅰ?/p>
問題原因
過長參數(shù)列可能是將多個算法并到一個函數(shù)中時發(fā)生的拧揽。函數(shù)中的入?yún)⒖梢杂脕砜刂谱罱K選用哪個算法去執(zhí)行。
過長參數(shù)列也可能是解耦類之間依賴關(guān)系時的副產(chǎn)品腺占。例如淤袜,用于創(chuàng)建函數(shù)中所需的特定對象的代碼已從函數(shù)移動到調(diào)用函數(shù)的代碼處,但創(chuàng)建的對象是作為參數(shù)傳遞到函數(shù)中湾笛。因此饮怯,原始類不再知道對象之間的關(guān)系,并且依賴性也已經(jīng)減少嚎研。但是如果創(chuàng)建的這些對象蓖墅,每一個都將需要它自己的參數(shù),這意味著過長參數(shù)列临扮。
太長的參數(shù)列難以理解论矾,太多參數(shù)會造成前后不一致、不易使用杆勇,而且一旦需要更多數(shù)據(jù)贪壳,就不得不修改它。
解決方案
- 如果向已有的對象發(fā)出一條請求就可以取代一個參數(shù)蚜退,那么你應(yīng)該使用 以函數(shù)取代參數(shù)(Replace Parameter with Methods) 闰靴。在這里,钻注,“已有的對象”可能是函數(shù)所屬類里的一個字段蚂且,也可能是另一個參數(shù)。
- 你還可以運(yùn)用 保持對象完整(Preserve Whole Object) 將來自同一對象的一堆數(shù)據(jù)收集起來幅恋,并以該對象替換它們杏死。
- 如果某些數(shù)據(jù)缺乏合理的對象歸屬,可使用 引入?yún)?shù)對象(Introduce Parameter Object) 為它們制造出一個“參數(shù)對象”捆交。
收益
- 更易讀淑翼,更簡短的代碼。
- 重構(gòu)可能會暴露出之前未注意到的重復(fù)代碼品追。
何時忽略
- 這里有一個重要的例外:有時候你明顯不想造成"被調(diào)用對象"與"較大對象"間的某種依賴關(guān)系玄括。這時候?qū)?shù)據(jù)從對象中拆解出來單獨(dú)作為參數(shù),也很合情理肉瓦。但是請注意其所引發(fā)的代價惠豺。如果參數(shù)列太長或變化太頻繁银还,就需要重新考慮自己的依賴結(jié)構(gòu)了。
重構(gòu)方法說明
以函數(shù)取代參數(shù)(Replace Parameter with Methods)
問題
對象調(diào)用某個函數(shù)洁墙,并將所得結(jié)果作為參數(shù)蛹疯,傳遞給另一個函數(shù)。而接受該參數(shù)的函數(shù)本身也能夠調(diào)用前一個函數(shù)热监。
解決
讓參數(shù)接受者去除該項(xiàng)參數(shù)捺弦,并直接調(diào)用前一個函數(shù)。
保持對象完整(Preserve Whole Object)
問題
你從某個對象中取出若干值孝扛,將它們作為某一次函數(shù)調(diào)用時的參數(shù)列吼。
解決
改為傳遞整個對象。
引入?yún)?shù)對象(Introduce Parameter Object)
問題
某些參數(shù)總是很自然地同時出現(xiàn)苦始。
解決
以一個對象來取代這些參數(shù)寞钥。
作者:易水人去丶明月如霜
鏈接:http://www.reibang.com/p/065e6742a07b
個人總結(jié)
一個良好的程序員,良好的編程習(xí)慣是首要條件陌选,如果前期代碼寫的直觀理郑,清楚,不管那種語言都是比較好維護(hù)的咨油。
文檔是很必要寫的您炉,例如一些接口,協(xié)議等役电,這些必須做下注釋赚爵,以及文檔的說明,不然后面比較難維護(hù)
盡量把任務(wù)和模塊拆分的合理一點(diǎn)法瑟,小一些冀膝,這樣利于掌控和維護(hù);
至少要求每個人他自己的風(fēng)格要統(tǒng)一霎挟;
建立一個公開的測試框架窝剖,增強(qiáng)測試力度,員工在公開的場合看到自己寫的東西每次BUG都很多氓扛,對其會有一定的鞭策作用;
最多不超過一周论笔,要對服務(wù)器上的源碼進(jìn)行整體編譯一次采郎;