天天看點

代碼重構(五):繼承關系重構規則

陸陸續續的發表了多篇關于重構的文章了,還是那句話,重構是一個項目疊代開發中必不可少的一個階段。其實重構伴随着你的項目的整個階段。在前幾篇關于重構的文章中我們談到了函數的重構、類的重構、資料的重構以及條件表達式的重構,那麼今天咱們就來聊聊繼承關系的重構。當然還是延續前幾篇部落格的風格,我們在部落格中的代碼執行個體依然使用Swift語言來實作,當然還是那句話,使用什麼語言無所謂,關鍵是看重構的場景以及重構的思想。

“重構”不僅僅可以改善你既有的代碼設計,還可以改變你組織代碼的思路,使你的程式在設計之初就趨于合理化,利于程式的擴充。重構往往伴随着設計模式的使用,在重構系列的部落格結束後,我想系統的給大家分享一下關于設計模式的東西。當然是結合着各種執行個體。所謂一名Coder,重構和設計模式是必須涉獵的部分,因為這兩者可以讓你寫出更漂亮的代碼,當然要想真正的掌握設計模式以及各種重構手法,還得結合不同的執行個體來進行實踐。理論固然重要,但是要想将理論的東西變成你自己的,還必須将理論付諸實踐。廢話少說,進入今天的主題。

一.Pull Up Field (字段上移) & Pull Down Field (字段下移)

字段上移與字段下移是相對的,也是我們之前所說的“凡事都有其兩面性”,我們要辯證的去看待。我們隻對Pull Up Field (字段上移) 這個規則做讨論,那麼關于Pull Down Field (字段下移)我們不做過多的讨論,因為這兩條規則是相反的,了解一條後,把這條規則反過來就是我們要了解的另一條規則。這樣說起來,還是比“舉一反三”要容易的多。

下方這個執行個體是為了解釋“字段上移”所實作的一個Demo。當然Demo看上去不僅簡單而且是有些誇張的,不過說明字段上移這個規則是完全足夠了的。比如我們有一個父類為MySuperClass,我們有一個子類SubClass1,而在SubClass1中有一個字段父類是沒有的。因為後期需求疊代或者需求變更,我們需要再建立一個SubClass1的兄弟類,就是下方的SubClass2。在SubClass2中與SubClass1中存在相同的字段,那就是var a = 0。

代碼重構(五):繼承關系重構規則

 在上述情況下,就需要使用到我們的“字段上移”的規則。也就是說将子類中相同的字段移到父類中。在該執行個體中就是講var a = 0 移到父類中。重構後的代碼如下所示:

代碼重構(五):繼承關系重構規則

而将“Pull Down Field (字段下移)”正好與上面的情況相反。也就是父類中有某些字段,但是這些字段隻有在少數子類中使用到,在這種情況下我們需要将這個字段移到相應的子類中即可。除了Pull Up Field (字段上移) & Pull Down Field (字段下移) 這兩個規則外,Pull Up Method (将函數上移) 和 Pull Down Method (将函數下移)這兩個規則與上述情況類似。就是将上面的字段改成函數,有時候不僅字段會出現上述情況,函數也會出現上述情況,需要我們進行移動。因為使用場景類似,再次就不做過多的贅述了。

二、Extract Subclass (提煉子類)

這種情況下用的還是比較多的,當類中的某些方法隻有在特定的類的執行個體中才會使用到,此時我們就需要提煉出一個子類,将該方法放到相應的子類中。這樣一來我們的每個類的職責更為單一,這也就是我們常說的“單一職責”。

在下方示例中,CustomerBook是一個圖書消費者的類。其中customeCharge()方法是普通使用者計算消費金額所需的方法,而vipCharge()方法是VIP使用者調用的方法,在内部vipCharge()需要調用customeCharege()方法。但是對外部而言,vipCharge()方法隻有VIP使用者才會用到,在這種情況下我們就需要使用“Extract Subclass (提煉子類)”規則對VIP進行提煉。

代碼重構(五):繼承關系重構規則

具體做法是我們需要提煉出一個子類,也就是說将VIP使用者作為普通使用者的子類,然後将隻有VIP使用者才調用的方法放到我們的VIP子類中。這樣一來層次更加明确,每個類的職責更為單一。上述示例重構後的結果如下所示。

代碼重構(五):繼承關系重構規則

與“提煉子類”規則相對應的是“Collapse Hierarchy (折疊繼承關系)”。一句話來概括:就是當你的父類與子類差别不大時,我們就可以将子類與父類進行合并。将上面的示例翻轉就是“Collapse Hierarchy (折疊繼承關系)”規則的示例,再次就不做過多的贅述了。

三、Form Template Method (構造模闆函數)

Form Template Method (構造模闆函數)這一規則還是比較實用的。先說模闆,“模闆”其實就是架構,沒有具體的實作細節,隻有固定不變的步驟,可以說模闆不關心具體的細節。舉個栗子🌰,像前段時間比較火的“秘密花園”,那些沒有顔色的線條就是模闆,如果一些人擷取的是同一本秘密花園,那麼說明每個人所擷取的模闆是相同的。但是每個人對每塊的區域所圖的顔色又有差異,這就是實作細節的不同。

言歸正傳,當兩個兄弟類中的兩個函數中的實作步驟大緻一直,但是具體細節不同。在這種情況下,我們就可以将大體的步驟提取成模闆,放到父類中,而具體細節由各自的子類來實作。具體實作請看下方的類,在Subclass1和Subclass2中的calculate()方法中的大體步驟是相同的,就是對兩個值相加,然後傳回這兩個值的和。但是具體細節不同,可以看出兩個相加值的具體計算方式不同。

代碼重構(五):繼承關系重構規則

在上述情況下我們就可以使用“Form Template Method (構造模闆函數)”規則将相同的計算流程進行提取,也就是構造我們的模闆函數。将模闆函數放到兩個類的父類中,然後在相應的子類中隻給出實作細節即可。下方代碼段是重構後的代碼,父類中多出的方法就是我們提取的模闆函數,而子類中隻給出相應的實作細節即可。

代碼重構(五):繼承關系重構規則

四、以委托取代繼承(Replace Inheritance with Delegation)

有時候我們為一些類建立子類後,發現子類隻使用了父類的部分方法,而且沒有繼承或者部分繼承了父類的資料。在這種情況下我們就可以将這種繼承關系修改成委托的關系。具體做法就是修改這種繼承關系,在原有子類中添加父類的對象字段,在子類中建立相應的方法,在方法中使用委托對象來調用原始父類中相應的方法。

下方示例是我們假想出來的,但是說明該規則是綽綽有餘了。我們假設SubClass01類中隻會用到SuperClass01中的display()方法,而沒有繼承父類中的資料。在下方示例中是繼承關系,在這種情況下我們需要将其轉換成委托關系。

代碼重構(五):繼承關系重構規則

下方是我們重構後的代碼,在下方代碼中我們去除了之前的繼承關系。并在子類中建立了一個之前父類的代理對象,并且建立了一個相應的方法,在該建立的方法中通過代理對象來調用相應的方法。具體如下所示。

代碼重構(五):繼承關系重構規則

上述規則與以繼承取代委托(Replace Delegation with Inheritance)原則相對于,使用情況與上述相反,再次就不做過多的贅述了。

幾天部落格就先到這兒,内容比較簡單,但是還是比較重要的。

上述Demo分享位址:https://github.com/lizelu/CodeRefactoring-Swift

作者:青玉伏案

出處:http://www.cnblogs.com/ludashi/

本文版權歸作者和共部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

如果文中有什麼錯誤,歡迎指出。以免更多的人被誤導。

收履歷:某網際網路公司,招聘iOS/Android靠譜工程師,入職後,可内部聯系樓主,有小禮品贈送,有意者可郵箱投遞履歷:[email protected]