對(duì)于每個(gè)編碼人員來(lái)說(shuō),避免重復(fù)代碼可能是大家都想做的。對(duì)于有一定經(jīng)驗(yàn)(對(duì)基本的OO原則有一定經(jīng)驗(yàn))的開(kāi)發(fā)人員來(lái)說(shuō),大部分情況下都能比較自然地避免重復(fù)代碼的問(wèn)題,寫(xiě)代碼的時(shí)候,感覺(jué)有邏輯重復(fù)的情況,會(huì)很自然的憑感覺(jué)經(jīng)驗(yàn)做相應(yīng)的處理和復(fù)用。 以下是個(gè)人經(jīng)驗(yàn),供新手參考。
既然我們?cè)谟肑ava之類(lèi)的面向?qū)ο蟮恼Z(yǔ)言編碼,那么重復(fù)代碼可以大致分為如下兩種情況:
1、類(lèi)型體系之內(nèi)(父類(lèi)型和子類(lèi)型、子類(lèi)型之間)存在重復(fù)邏輯代碼
2、類(lèi)型體系之外的重復(fù)代碼
【類(lèi)型體系內(nèi)的重復(fù)代碼處理】

1、如果重復(fù)代碼屬于類(lèi)型本身操作(即應(yīng)該是以實(shí)例方法存在),則很自然的應(yīng)用重構(gòu)技巧,公共代碼往上走。如果Sub Type之間有這種重復(fù)代碼,把重復(fù)代碼遷移到DefaultAdatper中。
2、如果重復(fù)代碼不屬于類(lèi)型本身操作(即應(yīng)該是以靜態(tài)方法存在),則需要判斷一下這種靜態(tài)代碼的功能使用范圍:
A、如果是非常全局性的,例如有關(guān)java流的輔助操作,則應(yīng)該果斷的抽取出來(lái),封裝到一個(gè)Utility工具類(lèi)中,例如可以叫做IOUtil。把這個(gè)Utility類(lèi)放置到非常底層模塊中,這樣上層很多功能模塊中都可以使用,否則可能會(huì)導(dǎo)致上層多個(gè)模塊中都有類(lèi)似IOUtil的類(lèi),又是重復(fù)代碼。
1 public class IOUtil {
2 /**
3 * 工具類(lèi),不需要產(chǎn)生實(shí)例。 但是也不需要應(yīng)用單態(tài)!!!
4 */
5 private IOUtil() {}
6
7 public static InputStream buildInputSteam(File file) {//
}
8
9 //其他公共靜態(tài)操作
10 }
B、如果這種靜態(tài)操作只對(duì)本類(lèi)型體系有意義,則有兩種常用的處理方法:第一種是把這種靜態(tài)方法遷移到基類(lèi)DefaultAdapter中,但是不要在DefaultAdapter中放置過(guò)多的類(lèi)似靜態(tài)方法;第二種是把這種靜態(tài)方法封裝到一個(gè)helper助手類(lèi)中,例如MyTypeHelper,其中放置了MyType類(lèi)型體系中需要使用的一些靜態(tài)方法。如果第一種DefaultAdapter中堆放了較多的靜態(tài)方法,則可以用helper助手類(lèi)的方式。
1 public class MyTypeHelper {
2 /**
3 * 助手類(lèi),不需要產(chǎn)生實(shí)例。 但是也不需要應(yīng)用單態(tài)!!!
4 */
5 private MyTypeHelper() {}
6
7 public static boolean validateParamer(Object paramer) {//
}
8
9 //其他公共靜態(tài)操作
10 }
這個(gè)helper一般需要和接口、默認(rèn)適配類(lèi)一起暴露,便于擴(kuò)展子類(lèi)型使用。示意圖如下:

【類(lèi)型體系之外的重復(fù)代碼處理】
類(lèi)型體系之外的重復(fù)代碼處理相對(duì)就很簡(jiǎn)單了,根據(jù)重復(fù)代碼功能適用范圍,封裝到對(duì)應(yīng)的Util類(lèi)或者Helper類(lèi)中。這里就不細(xì)講了~_~
【有關(guān)公用代碼的幾個(gè)概念】
個(gè)人意見(jiàn),僅供參考。
助手類(lèi)(Helper class):我覺(jué)得首先這個(gè)類(lèi)產(chǎn)生的目的是為特定模塊或者特定功能服務(wù)的(助手嗎~_~),不是全局的。而且完全可以隱藏在特定模塊內(nèi)部,很多時(shí)候不需要暴露。Helper類(lèi)的命名要有針對(duì)性,不能搞成一個(gè)麻辣燙,里面的靜態(tài)操作既為這種功能服務(wù),又為那種功能服務(wù),盡量做個(gè)忠臣,不要同時(shí)當(dāng)多個(gè)主子的助手。
工具類(lèi)(Utility class):一般是全局的,往往有一定普世價(jià)值,也就是說(shuō)往往是全局通用的。
例如你在做一個(gè)模塊,這個(gè)模塊功能是處理表單,則關(guān)于處理表單的一些公用靜態(tài)操作就應(yīng)該放置到該模塊的一個(gè)助手類(lèi)中,名稱(chēng)類(lèi)似于FormProcesserHelper。再有一個(gè)導(dǎo)出報(bào)表的功能,則對(duì)應(yīng)的助手類(lèi)可以稱(chēng)之為ExportReportHelper,建議這兩個(gè)helper不要混在一起。 有人可能會(huì)說(shuō),這樣會(huì)不會(huì)導(dǎo)致大量的助手類(lèi)呢?這邊有個(gè)粒度把握的問(wèn)題(經(jīng)驗(yàn)會(huì)發(fā)生作用~_~),但是只要是助手類(lèi)命名規(guī)范,則一個(gè)助手類(lèi)的名字就基本上可以告訴用戶(hù)你提供什么樣的服務(wù)了。
假如你現(xiàn)在處理的是有關(guān)IO操作的重復(fù)代碼,則需要遷移到全局的工具類(lèi)中,因?yàn)檫@樣的操作往往適應(yīng)于全局的。
Facade class(門(mén)面類(lèi)):這個(gè)乍看起來(lái)和助手類(lèi)有點(diǎn)像,往往是綁定于特定模塊。但是,要搞清楚,門(mén)面類(lèi)是用來(lái)封裝子系統(tǒng)的,代理對(duì)模塊常用核心功能的訪(fǎng)問(wèn)的,針對(duì)用戶(hù)需要的常用場(chǎng)景提供一些輔助操作,幫助用戶(hù)更好的使用此模塊的主要功能。面向客戶(hù)端或者其他子系統(tǒng)或模塊的,不是用來(lái)處理對(duì)應(yīng)模塊中重復(fù)代碼的!!!有關(guān)詳細(xì)信息,請(qǐng)參加Facade設(shè)計(jì)模式的文檔。
【注意】Helper class、Utility class、Facade class一般都不需要生實(shí)例,暴露的都是靜態(tài)操作,更不需要誤寫(xiě)成單態(tài),別濫用單態(tài)!!!
后記::
關(guān)于重復(fù)代碼的處理,個(gè)人以為既需要技巧(別人總結(jié)出來(lái)的技巧),更需要經(jīng)驗(yàn)(經(jīng)驗(yàn)往往給你感覺(jué),跟著感覺(jué)走一般就不會(huì)太離譜~_~)。 希望對(duì)開(kāi)發(fā)新手有作用~_~
本博客中的所有文章、隨筆除了標(biāo)題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請(qǐng)注明出處,謝謝!