西西軟件園多重安全檢測(cè)下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁(yè)編程開(kāi)發(fā)其它知識(shí) → 《重構(gòu)之美》之避免復(fù)制與粘貼

《重構(gòu)之美》之避免復(fù)制與粘貼

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:本站整理時(shí)間:2010/12/1 18:52:01字體大。A-A+

作者:佚名點(diǎn)擊:33次評(píng)論:0次標(biāo)簽: 重構(gòu)之美 復(fù)制 粘貼

DVDFab PlatinumV9.2.0.1 Final 多國(guó)語(yǔ)言官方安裝版
  • 類型:光盤(pán)工具大小:74.4M語(yǔ)言:中文 評(píng)分:6.0
  • 標(biāo)簽:
立即下載
在開(kāi)發(fā)過(guò)程中,當(dāng)你發(fā)現(xiàn)代碼可以Copy-paste時(shí),就意味著代碼出現(xiàn)了重復(fù)。這是一種典型的反模式。William J.Brown等在著作AntiPatterns-Refactoring Software,Architecture, and Projects in Crisis(即《反模式——危機(jī)中軟件、架構(gòu)和項(xiàng)目的重構(gòu)》)中認(rèn)為這種形式的復(fù)用讓開(kāi)發(fā)的代碼行數(shù)量虛假地增加,但是不能像其他形式的復(fù)用一樣降低成本。Copy-Paste代碼的方式違背了DRY(即不要重復(fù)你自己)原則,使得多處地方出現(xiàn)了同樣或者相似的代碼。這是一種征兆,一旦在方法中或方法之間開(kāi)始Copy-Paste操作,就意味著需要采用Extract Method重構(gòu)手法。在提取方法之后,還可以根據(jù)情況利用Move Method重構(gòu)手法,將其搬移到一個(gè)類中,然后在原來(lái)的調(diào)用處轉(zhuǎn)為對(duì)該類方法的調(diào)用;蛘呃肦eplace Method with Method Object,將這些職責(zé)封裝為專有的類。


在我的編程生涯中,碰到類似Copy-Paste的情況簡(jiǎn)直不勝枚舉。在一次項(xiàng)目中,我們對(duì)開(kāi)源項(xiàng)目Jasper Report進(jìn)行了擴(kuò)展。我們加入了對(duì)新報(bào)表類型(CJT_REPORT)的支持。在ReportParameterAction類中,我們需要對(duì)報(bào)表對(duì)象ReportUnit判斷報(bào)表類型。于是,我在ReportParameterAction類中定義了如下的私有方法:

private void setReportUnitTypeByFileResource(ReportUnit reportUnit) {

final String JS_FILE_TYPE = "jrxml";

ResourceReference reference = reportUnit.getMainReport();

if (reference.isLocal()) {

FileResource resource = (FileResource)reference.getLocalResource();

String fileType = resource.getFileType();

if (fileType.toLowerCase().equals(JS_FILE_TYPE)){

reportUnit.setReportType(ReportUnit.JS_REPORT);

} else {

reportUnit.setReportType(ReportUnit.CJT_REPORT);

}

}

}




該方法根據(jù)FileResource中的文件類型獲得對(duì)應(yīng)的報(bào)表類型。這一方法在ReportParameterAction類的createWrappers()方法中被調(diào)用。

protected Event createWrappers(RequestContext context) {

ReportUnit reportUnit = loadReportUnit(context);

setReportUnitTypeByFileResource(reportUnit);

InitialRequestContext(context, reportUnit);



int reportType = reportUnit.getReportType();

if (reportType == ReportUnit.CJT_REPORT) {//……}

//……

}


后來(lái),我發(fā)現(xiàn)在EngineServiceImpl類中同樣需要判斷報(bào)表的類型。然而,setReportUnitTypeByFileResource()方法卻被定義為ReportParameterAction的私有方法,無(wú)法被EngineServiceImpl對(duì)象調(diào)用。最簡(jiǎn)單的做法是采用復(fù)制的方式,將這段代碼復(fù)制到EngineServiceImpl中。好了,如果此時(shí)我們不能忍住copy-paste的簡(jiǎn)便所帶來(lái)的誘惑,或許就會(huì)陷入重復(fù)的泥沼了。Copy的動(dòng)作絕對(duì)應(yīng)該鳴起刺耳的警聲。我們需要對(duì)這一做法保持足夠的警惕。



通過(guò)分析setReportUnitTypeByFileResource()方法,我發(fā)現(xiàn)該方法需要操作的對(duì)象均與ReportUnit有關(guān),而本身該方法的職責(zé)就是要獲得ReportUnit的類型,并對(duì)其字段reportType進(jìn)行設(shè)置,因此,完全可以將它搬移到ReportUnit中(Move Method重構(gòu),不是嗎?)。由于ReportUnit已經(jīng)增加了對(duì)reportType字段的get和set訪問(wèn)方法,我發(fā)現(xiàn)它們與我要重構(gòu)的方法實(shí)有異曲同工之處,因而決定將其搬移到getReportType()方法中:

public int getReportType() {

if (hasReportTypeBeenSet()) {

return reportType;

}

return getReportTypeByFileResource();


}

private int getReportTypeByFileResource() {


final String CJT_FILE_TYPE = "cjtxml";

int reportType = ReportUnit.JS_REPORT;

ResourceReference reference = this.getMainReport();

if (reference != null) {

if (reference.isLocal()) {

FileResource resource = (FileResource) reference

.getLocalResource();

if (resource != null) {

String fileType = resource.getFileType();

if (fileType.toLowerCase().equals(CJT_FILE_TYPE)) {

reportType = ReportUnit.CJT_REPORT;

}

}

}

}

return reportType;

}



private boolean hasReportTypeBeenSet(){

if (reportType != ReportUnit.JS_REPORT

&& reportType != ReportUnit.CJT_REPORT) {

return false;

} else {

return true;

}

}

注意,在以上過(guò)程中,除了使用Move Method之外,我還運(yùn)用了Rename Method以及Extract Method等重構(gòu)手法。


現(xiàn)在,對(duì)報(bào)表類型的獲取與調(diào)用就變得簡(jiǎn)單了,在ReportParameterAction與EngineServiceImpl類中,也規(guī)避了重復(fù)代碼的產(chǎn)生。例如,在createWrappers()方法中的調(diào)用被更改為:

protected Event createWrappers(RequestContext context) {

ReportUnit reportUnit = loadReportUnit(context);

       setReportUnitTypeByFileResource(reportUnit); 


InitialRequestContext(context, reportUnit);



int reportType = reportUnit.getReportType();

if (reportType == ReportUnit.CJT_REPORT) {//……}

//……

}

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門(mén)評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(0)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)