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

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

4.2重構(gòu)作法

如上圖所示,將每種type code重構(gòu)成subclass,加強(qiáng)了每種類(lèi)型處理業(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);
}
說(shuō)明:調(diào)用者無(wú)需了解具體的類(lèi)型,由View自身作判斷,返回EditMode接口,從而實(shí)現(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é)語(yǔ)
由上述案例可看到,引入subclass代替type code可以大大減少if-else判斷,而且可以把責(zé)任內(nèi)聚到每種type中,使代碼結(jié)構(gòu)更清晰易懂。
在本案例中引入了空類(lèi)型概念,即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;
}
}
說(shuō)明:空類(lèi)型保證了調(diào)用每個(gè)方法都有默認(rèn)值返回,而不需要進(jìn)行非空判斷,當(dāng)View沒(méi)有類(lèi)型時(shí),即返回默認(rèn)的空類(lèi)型
原創(chuàng)人員:Nicholas
文章來(lái)源:
http://www.cnblogs.com/obpm/archive/2010/07/13/1776856.html
posted on 2010-07-13 23:22
obpm 閱讀(231)
評(píng)論(0) 編輯 收藏 所屬分類(lèi):
架構(gòu)設(shè)計(jì)