陸陸續續的發表了多篇關於重構的文章了,仍是那句話,重構是一個項目迭代開發中必不可少的一個階段。其實重構伴隨着你的項目的整個階段。在前幾篇關於重構的文章中咱們談到了函數的重構、類的重構、數據的重構以及條件表達式的重構,那麼今天我們就來聊聊繼承關係的重構。固然仍是延續前幾篇博客的風格,咱們在博客中的代碼實例依然使用Swift語言來實現,固然仍是那句話,使用什麼語言無所謂,關鍵是看重構的場景以及重構的思想。git
「重構」不只僅能夠改善你既有的代碼設計,還能夠改變你組織代碼的思路,使你的程序在設計之初就趨於合理化,利於程序的擴充。重構每每伴隨着設計模式的使用,在重構系列的博客結束後,我想系統的給你們分享一下關於設計模式的東西。固然是結合着各類實例。所謂一名Coder,重構和設計模式是必須涉獵的部分,由於這二者可讓你寫出更漂亮的代碼,固然要想真正的掌握設計模式以及各類重構手法,還得結合不一樣的實例來進行實踐。理論當然重要,可是要想將理論的東西變成你本身的,還必須將理論付諸實踐。廢話少說,進入今天的主題。github
一.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 移到父類中。重構後的代碼以下所示:spa
而將「Pull Down Field (字段下移)」正好與上面的狀況相反。也就是父類中有某些字段,可是這些字段只有在少數子類中使用到,在這種狀況下咱們須要將這個字段移到相應的子類中便可。除了Pull Up Field (字段上移) & Pull Down Field (字段下移) 這兩個規則外,Pull Up Method (將函數上移) 和 Pull Down Method (將函數下移)這兩個規則與上述狀況相似。就是將上面的字段改爲函數,有時候不只字段會出現上述狀況,函數也會出現上述狀況,須要咱們進行移動。由於使用場景相似,再次就不作過多的贅述了。設計
2、Extract Subclass (提煉子類)3d
這種狀況下用的仍是比較多的,當類中的某些方法只有在特定的類的實例中才會使用到,此時咱們就須要提煉出一個子類,將該方法放到相應的子類中。這樣一來咱們的每一個類的職責更爲單一,這也就是咱們常說的「單一職責」。代理
在下方示例中,CustomerBook是一個圖書消費者的類。其中customeCharge()方法是普通用戶計算消費金額所需的方法,而vipCharge()方法是VIP用戶調用的方法,在內部vipCharge()須要調用customeCharege()方法。可是對外部而言,vipCharge()方法只有VIP用戶纔會用到,在這種狀況下咱們就須要使用「Extract Subclass (提煉子類)」規則對VIP進行提煉。orm
具體作法是咱們須要提煉出一個子類,也就是說將VIP用戶做爲普通用戶的子類,而後將只有VIP用戶才調用的方法放到咱們的VIP子類中。這樣一來層次更加明確,每一個類的職責更爲單一。上述示例重構後的結果以下所示。
與「提煉子類」規則相對應的是「Collapse Hierarchy (摺疊繼承關係)」。一句話來歸納:就是當你的父類與子類差異不大時,咱們就能夠將子類與父類進行合併。將上面的示例翻轉就是「Collapse Hierarchy (摺疊繼承關係)」規則的示例,再次就不作過多的贅述了。
3、Form Template Method (構造模板函數)
Form Template Method (構造模板函數)這一規則仍是比較實用的。先說模板,「模板」其實就是框架,沒有具體的實現細節,只有固定不變的步驟,能夠說模板不關心具體的細節。舉個栗子🌰,像前段時間比較火的「祕密花園」,那些沒有顏色的線條就是模板,若是一些人獲取的是同一本祕密花園,那麼說明每一個人所獲取的模板是相同的。可是每一個人對每塊的區域所圖的顏色又有差別,這就是實現細節的不一樣。
言歸正傳,當兩個兄弟類中的兩個函數中的實現步驟大體一直,可是具體細節不一樣。在這種狀況下,咱們就能夠將大致的步驟提取成模板,放到父類中,而具體細節由各自的子類來實現。具體實現請看下方的類,在Subclass1和Subclass2中的calculate()方法中的大致步驟是相同的,就是對兩個值相加,而後返回這兩個值的和。可是具體細節不一樣,能夠看出兩個相加值的具體計算方式不一樣。
在上述狀況下咱們就可使用「Form Template Method (構造模板函數)」規則將相同的計算流程進行提取,也就是構造咱們的模板函數。將模板函數放到兩個類的父類中,而後在相應的子類中只給出實現細節便可。下方代碼段是重構後的代碼,父類中多出的方法就是咱們提取的模板函數,而子類中只給出相應的實現細節便可。
4、以委託取代繼承(Replace Inheritance with Delegation)
有時候咱們爲一些類建立子類後,發現子類只使用了父類的部分方法,並且沒有繼承或者部分繼承了父類的數據。在這種狀況下咱們就能夠將這種繼承關係修改爲委託的關係。具體作法就是修改這種繼承關係,在原有子類中添加父類的對象字段,在子類中建立相應的方法,在方法中使用委託對象來調用原始父類中相應的方法。
下方示例是咱們假想出來的,可是說明該規則是綽綽有餘了。咱們假設SubClass01類中只會用到SuperClass01中的display()方法,而沒有繼承父類中的數據。在下方示例中是繼承關係,在這種狀況下咱們須要將其轉換成委託關係。
下方是咱們重構後的代碼,在下方代碼中咱們去除了以前的繼承關係。並在子類中建立了一個以前父類的代理對象,而且建立了一個相應的方法,在該新建的方法中經過代理對象來調用相應的方法。具體以下所示。
上述規則與以繼承取代委託(Replace Delegation with Inheritance)原則相對於,使用狀況與上述相反,再次就不作過多的贅述了。
幾天博客就先到這兒,內容比較簡單,可是仍是比較重要的。