祖?zhèn)?/a>shi山代碼重構(gòu)實戰(zhàn)(01)-Extract Class提煉類

      網(wǎng)友投稿 788 2022-05-30

      某個類做了應(yīng)該由兩個類做的事。

      建立一個新類,將相關(guān)的字段和函數(shù)從舊類移到新類。

      動機(jī)

      一個類應(yīng)該是一個清楚的抽象,處理一些明確的責(zé)任。但實際工作中,類會不斷擴(kuò)展。你會在這兒加入一些功能,在那兒加入一些數(shù)據(jù)。給某個類添加一項新責(zé)任時,你會覺得不值得為這項責(zé)任分離出一個單獨(dú)的類。于是,隨著責(zé)任不斷增加,這個類會變得過分復(fù)雜。很快,你的類變成一團(tuán)亂麻。這樣的類往往含有大量函數(shù)和數(shù)據(jù),太大而不易理解。

      此時你需要考慮哪些部分可以分離出去,并將它們分離到一個單獨(dú)的類。如果某些數(shù)據(jù)和某些函數(shù)總是一起出現(xiàn),某些數(shù)據(jù)經(jīng)常同時變化甚至彼此相依,這就表示你應(yīng)該將它們分離出去。

      一個有用的測試,問你自己,若你搬移了某些字段和函數(shù),會發(fā)生啥事?其他字段和函數(shù)是否因此變得無意義?

      另一個往往在開發(fā)后期出現(xiàn)的信號是類的子類化方式。若發(fā)現(xiàn):

      子類化只影響類的部分特性

      或發(fā)現(xiàn)某些特性需要以一種方式來子類化,某些特性則需以另一種方式子類化

      這就意味你需要分解原來的類。

      做法

      決定如何分解類所負(fù)的責(zé)任。

      祖?zhèn)鱯hi山代碼重構(gòu)實戰(zhàn)(01)-Extract Class提煉類

      建立一個新類,用以表現(xiàn)從舊類中分離出來的責(zé)任。若舊類剩下的責(zé)任與舊類名稱不符,為舊類改名

      構(gòu)造舊類時,創(chuàng)建一個新類的實例,建立“從舊類訪問新類”的連接關(guān)系

      對你想搬移的每個字段,運(yùn)用【搬移字段】搬移之。每次更改后運(yùn)行測試。

      使用【搬移函數(shù)】將必要函數(shù)搬移到新類。先搬移較低層函數(shù)(也就是“被其他函數(shù)調(diào)用”多于“調(diào)用其他

      函數(shù)”者)。每次更改后運(yùn)行測試。

      檢查兩個類的接口,去掉不再需要的函數(shù),必要時為函數(shù)重新取一個適合新環(huán)境的名字。

      決定是否公開新的類。如果確實需要,考慮對新類應(yīng)用【將引用對象改為值對象】 使其成為一個值對象

      范例

      Person類:

      package com.javaedge.refactor.extract_class; import lombok.Data; /** * @author JavaEdge * @date 2022/3/30 */ @Data public class Person { private String name; private String officeAreaCode; private String officeNumber; public String getTelephoneNumber() { return this.officeAreaCode + this.officeNumber; } }

      可以將與電話號碼相關(guān)的行為分離到一個獨(dú)立的類。

      首先,定義一個空的 TelephoneNumber 類來表示“電話號碼”:

      class TelephoneNumber { }

      然后,建立從Person到TelephoneNumber的連接:

      class Person { private TelephoneNumber _officeTe1ephone = new TelephoneNumber() }

      現(xiàn)在,運(yùn)用MOVE Field 移動一個字段過來:

      package com.javaedge.refactor.extract_class; import lombok.Data; /** * @author JavaEdge * @date 2022/3/30 */ @Data public class Person { private String name; private String officeNumber; private TelephoneNumber officeTelephone = new TelephoneNumber(); public String getTelephoneNumber() { return getOfficeAreaCode() + this.officeNumber; } public String getOfficeAreaCode() { return officeTelephone.getAreaCode(); } public void setOfficeAreaCode(String areaCode) { officeTelephone.setAreaCode(areaCode); } }

      package com.javaedge.refactor.extract_class; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author JavaEdge * @date 2022/3/30 */ @Data @NoArgsConstructor @AllArgsConstructor public class TelephoneNumber { private String areaCode; }

      移動其它字段,并用 move method將相關(guān)方法移動到TelephoneNumber

      package com.javaedge.refactor.extract_class; import lombok.Data; /** * @author JavaEdge * @date 2022/3/30 */ @Data public class Person { private String name; private TelephoneNumber officeTelephone = new TelephoneNumber(); public String getTelephoneNumber() { return officeTelephone.getTelephoneNumber(); } }

      package com.javaedge.refactor.extract_class; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author JavaEdge * @date 2022/3/30 */ @Data @NoArgsConstructor @AllArgsConstructor public class TelephoneNumber { private String areaCode; private String number; public String getTelephoneNumber() { return this.areaCode + this.number; } }

      要不要對用戶公開這個新類?我可以將Person中與電話號碼相關(guān)的函數(shù)委托至TelephoneNumber,從而完全隠藏這個新類;也可以直接將它對用戶公開。我還可以將它公開給部分用戶(位于同一個包中的用戶),而不公開給其他用戶。

      如果我選擇公開新類,就需要考慮別名帶來的危險。如果我公開了TelephoneNumber,而有個用戶修改了對象中的areaCode字段值,我又怎么能知道呢?而且,做出修改的可能不是直接用戶,而是用戶的用戶的用戶。面對這個問題,我有下列幾種選擇。

      允許任何對象修改TelephoneNumber對象的任何部分。這就使得TelephoneNumber對象成為引用對象,于是我應(yīng)該考慮使用CZimigeValue to Reference(179)。這種情況下,Person應(yīng)該是TelephoneNumber的訪問點(diǎn)

      不許任何人不通過Person對象就修改TelephoneNumber對象,為此,可以將TelephoneNumber設(shè)為不可修改或為它提供一個不可修改的接口

      先復(fù)制一TelephoneNumber對象,然后將復(fù)制得到的新對象傳遞給用戶。但這可能會造成一定程度的迷惑,因為人們會認(rèn)為他們可以修改TelephoneNumber對象的值。此外,如果同個TelephoneNumber對象被傳遞給多個用戶,也可能在用戶之間造成別名問題

      電話號碼”對象一般還具有復(fù)用價值,因此我考慮將新提煉的類暴露給更多的客戶端。需要訪問TelephoneNumber對象時,只須把Person類中那些office開頭的訪問函數(shù)搬移過來并略作修改即可。但這樣TelephoneNumber就更像一個值對象了,因此我會先對它使用【將引用對象改為值對象】。

      Extract Class是改善并發(fā)程序的一種常用技術(shù),因為它使你可以為提煉后的兩個類分別加鎖。如果你不需要同時鎖定兩個對象,就不必這樣做。

      這里也存在危險性。如果需要確保兩個對象被同時鎖,就面臨事務(wù)問題,需要使用其他類型的共享鎖。這是一個復(fù)雜領(lǐng)域,比起一般情況需要更繁重的機(jī)制。事務(wù)很有實用性,但是編寫事務(wù)管理程序則超出了大多數(shù)程序員的職責(zé)范圍。

      Java

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:【鯤鵬經(jīng)典直播征文】+openEuler內(nèi)核熱升級,業(yè)務(wù)不停機(jī)
      下一篇:關(guān)于生物醫(yī)學(xué)信號處理與分析軟件系統(tǒng)設(shè)計的問題
      相關(guān)文章
      AV在线亚洲男人的天堂| 亚洲性无码AV中文字幕| 亚洲精品乱码久久久久久蜜桃图片| 亚洲一区免费观看| 中文字幕久久亚洲一区| 国产亚洲精品a在线观看| 亚洲国产精品一区二区第四页| 亚洲6080yy久久无码产自国产| 亚洲国产亚洲片在线观看播放| 亚洲国产日韩在线视频| 亚洲精品无码AV人在线播放| 亚洲综合无码精品一区二区三区| 亚洲一区日韩高清中文字幕亚洲| 亚洲国产aⅴ综合网| 亚洲精品国产高清不卡在线| 亚洲AV成人潮喷综合网| 亚洲国产综合无码一区二区二三区| 亚洲国产成人久久综合碰| 亚洲精品第一国产综合境外资源 | 亚洲欧洲精品一区二区三区| 久久精品亚洲一区二区三区浴池| 亚洲人成电影在线天堂| 78成人精品电影在线播放日韩精品电影一区亚洲 | 亚洲黄色免费在线观看| 老色鬼久久亚洲AV综合| 老色鬼久久亚洲AV综合| 亚洲国产精品线观看不卡| 亚洲国产成人99精品激情在线| 亚洲综合av一区二区三区不卡| 亚洲私人无码综合久久网| 亚洲AV永久无码精品网站在线观看| 国产成人综合亚洲| 亚洲天堂中文字幕在线| 黑人精品videos亚洲人| 蜜芽亚洲av无码精品色午夜| 亚洲乱码中文论理电影| 亚洲精品无AMM毛片| 亚洲视频人成在线播放| 国产亚洲av片在线观看播放| 亚洲国产成人精品不卡青青草原| 亚洲精品自拍视频|