以子類取代類型編碼
Replace Type Code with Subclasses
1. 何謂重構(gòu)
1.1名詞解釋
對軟件內(nèi)部結(jié)構(gòu)的一種調(diào)整,目的是在不改變「軟件之可察行為」前提下,提高其可理解性,降低其修改成本。
1.2動詞解釋
使用一系列重構(gòu)準(zhǔn)則(手法),在不改變「軟件之可察行為」前提下,調(diào)整其結(jié)構(gòu)。
2. 為何重構(gòu)
2.1「重構(gòu)」改進(jìn)軟件設(shè)計
同樣完成一件事,設(shè)計不良的程序往往需要更多代碼,這常常是因為代碼在不同的地方使用完全相同的語句做同樣的事。因此改進(jìn)設(shè)計的一個重要方向就是消除重復(fù)代碼(Duplicate Code)
2.2「重構(gòu)」使軟件更易被理解
你的源碼還有其它讀者:數(shù)個月之后可能會有另一位程序員嘗試讀懂你的代碼并做一些修改。我們很容易忘記這第二位讀者,但他才是最重要的。計算器是否多花了數(shù)個鐘頭進(jìn)行編譯,又有什么關(guān)系呢?如果一個程序員花費一周時間來修改某段代碼,那才關(guān)系重大— 如果他理解你的代碼,這個修改原本只需一小時
2.3「重構(gòu)」助你找到臭蟲 ( bugs)
Kent Beck 經(jīng)常形容自己的一句話:『我不是個偉大的程序員;我只是個有著一些優(yōu)秀習(xí)慣的好程序員而已。』重構(gòu)能夠幫助我更有效地寫出強固穩(wěn)?。╮obust)的代碼。
2.4「重構(gòu)」助你提高編程速度
終于,前面的一切都?xì)w結(jié)到了這最后一點:重構(gòu)幫助你更快速地開發(fā)程序。聽起來有違反直覺。當(dāng)我談到重構(gòu),人們很容易看出它能夠提高質(zhì)量。改善設(shè)計、提升可讀性、減少錯誤,這些都是提高質(zhì)量。但這難道不會降低開發(fā)速度嗎?我強烈相信:良好設(shè)計是快速軟件開發(fā)的根本。事實上擁有良好設(shè)計才可能達(dá)成快速的開發(fā)。如果沒有良好設(shè)計,或許某一段時間內(nèi)你的進(jìn)展迅速,但惡劣的設(shè)計很快就讓你的速度慢下來。你會把時間花在調(diào)試上面,無法添加新功能。修改時間愈來愈長,因為你必須花愈來愈多的時間去理解系統(tǒng)、尋找重復(fù)代碼。隨著你給最初程序打上一個又一個的補?。╬atch),新特性需要更多代碼才能實現(xiàn)。真是個惡性循環(huán)。
3.何時重構(gòu)?
重構(gòu)本來就不是一件「特別撥出時間做」的事情,重構(gòu)應(yīng)該隨時隨地進(jìn)行。你不應(yīng)該為重構(gòu)而重構(gòu),你之所以重構(gòu),是因為你想做別的什么事,而重構(gòu)可以幫助你把那些事做好
3.1三次法則(The Rule of Three)
Don Roberts 給了我一條準(zhǔn)則:第一次做某件事時只管去做;第二次做類似的事會產(chǎn)生反感,但無論如何還是做了;第三次再做類似的事,你就應(yīng)該重構(gòu)。
☆ 事不過三,三則重構(gòu)。(Three strikes and you refactor.)
3.2重構(gòu)時機
添加功能時一并重構(gòu)
修補錯誤時一并重構(gòu)
復(fù)審代碼時一并重構(gòu)
-以上章節(jié)摘抄自《重構(gòu)-改善既有代碼的設(shè)計》
4.平臺重構(gòu)案例
4.1重構(gòu)動機
1. 實例模塊為View,重構(gòu)元素為ViewAction、ViewProcessBean、View,以下為關(guān)系圖。

2. 由于View存在多種editMode(編輯模式),而每個調(diào)用的地方都需要進(jìn)行type code(類型碼)判斷,然后再進(jìn)行相應(yīng)的業(yè)務(wù)邏輯處理,最終在每個調(diào)用的地方都形成了大量的if-else代碼,大大減弱了代碼的可讀性,和邏輯清晰度。
3. 調(diào)用的地方:

4.2重構(gòu)作法

如上圖所示,將每種type code重構(gòu)成subclass,加強了每種類型處理業(yè)務(wù)邏輯的能力。
View-版本1566代碼片段:
public EditMode getEditModeType() {
if (EDIT_MODE_CODE_DQL.equals(getEditMode())) {
return new DQLEditMode(this);
} else if (EDIT_MODE_CODE_SQL.equals(getEditMode())) {
return new SQLEditMode(this);
} else if (EDIT_MODE_DESIGN.equals(getEditMode())) {
return new DesignEditMode(this);
}
return new NullEditMode(this);
}
說明:調(diào)用者無需了解具體的類型,由View自身作判斷,返回EditMode接口,從而實現(xiàn)多態(tài)調(diào)用。
ViewProcessBean代碼片段:
重構(gòu)前-版本1503:
public String expDocToExcel(String viewid, WebUser user, ParamsTable params) throws Exception {
if (view.getEditMode().equals(View.EDIT_MODE_DESIGN)) {
datas = dp.queryBySQLPage(sql, params, tempPage, LINES, user.getDomainid());
} else if (view.getEditMode().equals(View.EDIT_MODE_CODE_DQL)) {
datas = dp.queryByDQLPage(dql, params, tempPage, LINES, user.getDomainid());
} else if (view.getEditMode().endsWith(View.EDIT_MODE_CODE_SQL)) {
datas = dp.queryBySQLPage(sql, params, tempPage, LINES, user.getDomainid());
}
}
重構(gòu)后-版本1566:
public String expDocToExcel(String viewid, WebUser user, ParamsTable params) throws Exception {
datas = view.getEditModeType().getDataPackage(params, tempPage, LINES, user, currdoc);
//其他業(yè)務(wù)邏輯
}
5.結(jié)語
由上述案例可看到,引入subclass代替type code可以大大減少if-else判斷,而且可以把責(zé)任內(nèi)聚到每種type中,使代碼結(jié)構(gòu)更清晰易懂。
在本案例中引入了空類型概念,即NullEditMode,代碼如下:
/**
*
* @author nicholas zhen
*
*/
public class NullEditMode extends AbstractEditMode implements EditMode {
public NullEditMode(View view) {
super(view);
}
public String getQueryString(ParamsTable params, WebUser user, Document sDoc) {
return "";
}
public DataPackage getDataPackage(ParamsTable params, WebUser user, Document doc) throws Exception {
return new DataPackage();
}
public DataPackage getDataPackage(ParamsTable params, int page, int lines, WebUser user, Document doc) throws Exception {
return new DataPackage();
}
public long count(ParamsTable params, WebUser user, Document doc) throws Exception {
return 0;
}
}
說明:空類型保證了調(diào)用每個方法都有默認(rèn)值返回,而不需要進(jìn)行非空判斷,當(dāng)View沒有類型時,即返回默認(rèn)的空類型
原創(chuàng)人員:Nicholas
文章來源:
http://www.cnblogs.com/obpm/archive/2010/07/13/1776856.html
posted on 2010-07-13 23:22
obpm 閱讀(230)
評論(0) 編輯 收藏 所屬分類:
架構(gòu)設(shè)計