重新組織數(shù)據(jù)
1. Self Encapsulate Field(自封裝字段)
Q:你直接訪問一個字段鹰祸,但與字段之間的耦合關(guān)系逐漸變得笨拙
A:為這個字段建立取值/設(shè)值函數(shù),并且只以這些函數(shù)來訪問字段
間接訪問變量的好處是蕴坪,子類可以通過覆寫一個函數(shù)而改變獲取數(shù)據(jù)的途徑背传;支持延遲初始化等台夺。
2. Replace Data Value with Object(以對象取代數(shù)據(jù)值)
Q:你有一個數(shù)據(jù)項,需要與其他數(shù)據(jù)和行為一起使用才有意義梳星。
A:將數(shù)據(jù)項變?yōu)閷ο?/strong>
業(yè)務(wù)一開始可能僅僅需要一個數(shù)據(jù)值,后續(xù)慢慢加入針對數(shù)據(jù)值的各種行為和關(guān)聯(lián)數(shù)據(jù)前域,此時 Duplicate Code 和 Feature Envy 的壞味道就會逐漸暴露。
3. Change Value to Reference(將值對象改為引用對象)
Q:你從一個類衍生出許多彼此相等的實例匿垄,希望將它們替換為同一個對象椿疗。
A:將這個值對象變成引用對象届榄。
之所以需要將值對象改為引用對象倔喂,通常的考慮是一些重復(fù)的對象需要同步改動,更直接的例子就是單例對象攻晒。
引用對象應(yīng)該由靜態(tài)字典或者注冊表對象來管理班挖,應(yīng)該考慮預(yù)先創(chuàng)建好還是動態(tài)創(chuàng)建萧芙,通常需要考慮使用工廠模式進行創(chuàng)建假丧。
4. Change Reference to Value(將引用對象改為值對象)
Q:你有一個引用對象包帚,很小且不可變,而且不易管理疯趟。
A:將它變成一個值對象谋梭。
引用對象必須被以某種方式控制瓮床,你必須向其控制者請求適當?shù)膶ο蟛洹K鼈兛赡茉斐蓛?nèi)存區(qū)域之間錯綜復(fù)雜的關(guān)聯(lián)癣亚。而值對象获印,特別是不可變的值對象蓬豁,使你無需考慮同步問題。
可變的引用對象是不應(yīng)該變?yōu)橹祵ο蟮娜∧迹驗槟菍⒁馕吨阈枰紤]各個值對象之間數(shù)據(jù)同步的問題玩敏。
5. Replace Array with Object(以對象取代數(shù)組)
Q:你有一個數(shù)組质礼,其中的元素各自代表不同的東西。
A:以對象替換數(shù)組砰粹。對于數(shù)組中的每一個元素造挽,以一個字段來表示饭入。
假如一個數(shù)組的元素根據(jù)其下標具備不同的含義和行為以及數(shù)據(jù)解釋方式,則對象更適合表示這些數(shù)據(jù)爽航。
6. Duplicate Observed Data(復(fù)制“被監(jiān)視數(shù)據(jù)”)
Q:你有一些領(lǐng)域數(shù)據(jù)置身于 GUI 控件中乾忱,而領(lǐng)域函數(shù)需要訪問這些數(shù)據(jù)。
A:將該數(shù)據(jù)復(fù)制到一個領(lǐng)域?qū)ο笾写觯⒁粋€ Observer 模式寞肖,用以同步領(lǐng)域?qū)ο蠛?GUI 對象內(nèi)的重復(fù)數(shù)據(jù)。
簡單來說觅赊,“讓數(shù)據(jù)歸數(shù)據(jù)吮螺,讓顯示歸顯示”;而實現(xiàn)這一特性離不開觀察者模式萝风。
7. Change Unidirectional Association to Bidirectional(將單向關(guān)聯(lián)改為雙向關(guān)聯(lián))
Q:兩個類都需要使用對方的特性规惰,但其間只有一條單向連接
A:添加一個反向指針歇万,并使修改函數(shù)能夠同時更新兩條連接勋陪。
如何確定由誰控制雙向關(guān)聯(lián)關(guān)系:
- 如果兩者都是引用對象,且關(guān)聯(lián)關(guān)系是“一對多”的關(guān)系寒锚,那么就由“擁有單一引用”的那一方承擔“控制者”角色
- 如果某個對象是組成另一個對象的部件壕曼,那么由后者負責控制關(guān)聯(lián)關(guān)系
- 如果兩者是“多對多”的關(guān)系,由誰控制關(guān)聯(lián)關(guān)系都無所謂
8. Change Bidirectional Association to Unidirectional
Q:兩個類之間有雙向關(guān)聯(lián)摹蘑,但其中一個類如今不再需要另一個類的特性衅鹿。
A:去除不必要的關(guān)聯(lián)大渤。
維護雙向連接增加了復(fù)雜度,且容易造成內(nèi)存泄漏耕捞,增加模塊間耦合。
9. Replace Magic Number with Symbolic Constant(以字面常量取代魔法數(shù))
Q:你有一個字面數(shù)值敞映,帶有特別含義磷斧。
A:創(chuàng)造一個常量弛饭,根據(jù)其意義為它命名,并將上述的字面數(shù)值替換為這個常量档桃。
10. Encapsulate Field(封裝字段)
Q:你的類中存在一個 public 字段
A:將它聲明為 private胳蛮,并提供相應(yīng)的訪問函數(shù)仅炊。
11. Encapsulate Collection(封裝集合)
Q:有個函數(shù)返回一個集合抚垄。
A:讓這個函數(shù)返回該集合的一個只讀副本谋逻,并在這個類中提供添加/移除集合元素的函數(shù)毁兆。
取值函數(shù)不應(yīng)該返回集合自身气堕,因為這樣用戶修改集合內(nèi)容時集合擁有者將一無所知。
12. Replace Record with Data Class(以數(shù)據(jù)類取代記錄)
Q:你需要面對傳統(tǒng)編程環(huán)境中的記錄結(jié)構(gòu)揖膜。
A:為該記錄創(chuàng)建一個“啞”數(shù)據(jù)對象。
不要以代碼之外的規(guī)則約束代碼邏輯壹粟,例如以數(shù)組的不同下標來表示不同含義趁仙。
13. Replace Type Code with Class(以類取代類型碼)
Q:類之中有一個數(shù)值類型碼幸撕,但它并不影響類的行為。
A:以一個新的類替換該數(shù)值類型碼坐儿。
類型碼本質(zhì)上仍然是數(shù)值律胀,而非對象,因而編譯器無法做有效的類型檢查貌矿。
14. Replace Type Code with Subclasses(以子類取代類型碼)
Q:你有一個不可變的類型碼炭菌。
A:以子類取代這個類型碼。
在面向?qū)ο笮g(shù)語中逛漫,聽上去最高貴的詞非“多態(tài)”莫屬黑低。
將類型碼用子類封裝后,與類型碼相關(guān)的行為和特性也就可以封裝到子類中酌毡。
15. Replace Type Code with State/Strategy(以 State/Strategy 取代類型碼)
Q:你有一個類型碼克握,它會影響類的行為,但你無法通過繼承手法消除它枷踏。
A:以狀態(tài)對象取代類型碼菩暗。
16. Replace Subclass with Field(以字段取代子類)
Q:你的各個子類的唯一差別只在“返回常量數(shù)據(jù)”的函數(shù)身上。
A:修改這些函數(shù)停团,使它們返回超類中的某個(新增)字段旗芬,然后銷毀子類辆琅。
沒有行為只有數(shù)據(jù)的類應(yīng)當被移除暇屋。