Time of Update: 2018-12-07
你手上一個條件運算式,它根據物件類型的不同而選擇不同的行為。將這個條件運算式的每個分支放進一個子類的覆寫函數中,然後將原始函式宣告為抽象函數。動機:多態的最根本的好處是:如果你需要根據對象的不同類型而採取不同的行為,多態使你不必編寫某些的條件運算式。 正因為有了多態,所以你會發現:“類型嗎的switch語句”以及 ”基於類型名稱的if-then-else語句“在物件導向程式中很少出現。
Time of Update: 2018-12-07
你需要為服務類提供一些額外函數,但你無法修改這個類。建立一個新類,使它包含這些額外函數。讓這個擴充品成為源類的子類或封裝類。動機:類的作者無法預知未來,他們常常沒能為你預先準備一些有用的函數。如果你可能修改源碼,最後的辦法就是直接加入自己需要的函數。但你經常無法修改源碼。如果只需要一兩個函數,你可以使用 Introduce Foreign Method
Time of Update: 2018-12-07
有時你會看到這樣的對象:其內某個執行個體變數僅為某種特定情況而設。這樣的代碼讓人不易理解,因為你通常認為對象在所有時候都需要它的所有變數。在變數未被使用的情況下猜測當初設定目的,會讓你發瘋。 請使用Extract Class (提煉類)給這些變數創造一個家,然後把所有和這些變數相關的代碼都放進這個新家,也許你還可以使用 Introduce Null Object (引入Null 對象)在變數不合法的情況下建立一個null對象,從而避免寫出條件式代碼。
Time of Update: 2018-12-07
你有一個大型函數,其中對局部變數的使用使你無法採用 Extract Method (提煉函數)。將這個大型函數放進一個單獨對象中,如此一來局部變數就成了對象內的欄位。然後你可以在同一個對象中將這個大型函數分解為多個小型函數。 動機:局部變數的存在會增加函數分解的難度。如果一個函數之中局部變數泛濫,那麼想分解這個函數是非常困難的。Replace Temp with Query
Time of Update: 2018-12-07
[導讀][設計模式整理筆記 一] 基礎知識[設計模式整理筆記 二] 簡單原廠模式(Simple Factory)[設計模式整理筆記 三] 原廠模式(Factory)[設計模式整理筆記 四] 抽象原廠模式(Abstract Factory)[設計模式整理筆記 五] 建立者模式(Builder)[設計模式整理筆記 六] 原廠模式與建立者模式總結[設計模式整理筆記 七] 原型模式(ProtoType)[設計模式整理筆記 八] 單例模式(Singleton)[設計模式整理筆記
Time of Update: 2018-12-07
類中的某個欄位應該在對象建立時被設值,然後就不再改變。去掉該欄位的所有設值函數。動機:如果你為某個欄位提供了設值函數,這就暗示這個欄位值可以被改變。如果你不希望在對象建立之後此欄位還有機會被改變,那就不要為它提供設值函數。這樣你的意圖會更加清晰,並且可以排除其值被修改的可能性。 如果你保留了間接訪問變數的方法,就可能經常有程式員盲目使用它們。這些人甚至會在建構函式中使用設值函數。做法:1、檢查設值函數被使用方式,看它是否只是被建構函式調用,或者被建構函式所調用的另一個函數調用。
Time of Update: 2018-12-07
類之中有一個數實值型別碼,但它並不影響類的行為。以一個新的類替換該數實值型別碼。動機:在以C為基礎的程式設計語言中,類型碼或枚舉值很常見。如果帶著一個有意義的符號名,類型碼的可讀性還不錯。問題在於,符號名終究只是個別名,編譯器看見的、進行類型檢驗的,還是背後那個數值。任何接受類型碼作為參數的函數,所期望的實際上是一個數值,無法強制使用符號名。這會大大降低代碼的可讀性,從而成為bug之源。
Time of Update: 2018-12-07
你需要再三檢查某對象是否為null。將null值替換為null對象。動機:多態的最根本好處在於:你不必再向對象詢問“你是什麼類型”而後根據得到的答案調用對象的某個行為-你只管調用該行為就是了,其他的一切多態機制會為你安排妥當。當某個欄位內容是null時,多態可扮演另一個較不直觀的用途。做法:1、為源類建立一個子類,使其行為就像是源類的null版本。在源類和null子類中都加上IsNull()函數,前者的IsNull()應該返回false,後者的IsNull()返回true。
Time of Update: 2018-12-07
如果你看到使用者向一個對象請求另一個對象,然後再向後者請求另一個對象,然後再請求另一個對象……這就是訊息鏈。實際代碼中你看到的可能是一長串getThis()或一長串臨時變數。採取這種方式,意味客戶代碼將與尋找過程中的導航緊密耦合。一旦對象間關係發生任何變化,用戶端就不得不做出相應的修改。 這時候應該使用 Hide Delegate (隱藏委託關係)。你可以在訊息鏈的不同位置進行這種重構。理論上可以重構訊息鏈上任何對象,但這麼做往往會把一系列對象都變成Middle
Time of Update: 2018-12-07
你的程式有某個臨時變數被賦值超過一次,它既不是迴圈變數,也不被用於收集計算結果。針對每次賦值,創造一個獨立、對應的臨時變數double temp = 2 + (_height + _width); Console.WriteLine(temp); temp = _height * _width; Console.WriteLine(temp); const double perimeter = 2 + (_height + _
Time of Update: 2018-12-07
[導讀][設計模式整理筆記 一] 基礎知識[設計模式整理筆記 二] 簡單原廠模式(Simple Factory)[設計模式整理筆記 三] 原廠模式(Factory)[設計模式整理筆記 四] 抽象原廠模式(Abstract Factory)[設計模式整理筆記 五] 建立者模式(Builder)[設計模式整理筆記 六] 原廠模式與建立者模式總結[設計模式整理筆記 七] 原型模式(ProtoType)[設計模式整理筆記 八] 單例模式(Singleton)[設計模式整理筆記
Time of Update: 2018-12-07
2個類有相似特性。為這2個類建立一個超類,將相同特性移至超類。動機:重複代碼是系統中最糟糕的東西之一。如果你在不同地方做同一件事情,一旦需要修改那些動作,你就得平白做更多的修改。 重複代碼的某種形式就是:2個類以相同的方式做類似的事情,或者以不同的方式做類似的事情。對象提供了一種簡化這種情況的機制,那就是繼承。但是,在建立這些具有共通性的類之前,你往往無法發現這樣的共通性,因此常常會在具有共通性的類出現之後,再開始建立其間的繼承結構。 另一種選擇就是 Extract
Time of Update: 2018-12-07
有一個函數,從來沒有被其他任何類用到。將這個函數修改為private。動機:重構往往促使你修改函數的可見度。提高函數可見度的情況很容易想象:另一個類需要用到某個函數,因此你必須提高該函數的可見度。但是要指出一個函數的可見度是否過高,就稍微困難一些。理想狀態下,你可以使用工具檢查所有函數,指出可被隱藏起來的函數。即使沒有這樣的工具,你也應該時常進行這樣的檢查。
Time of Update: 2018-12-07
你有一個不可變的類型碼,它會影響類的行為。以子類取代這個類型碼。動機:如果你面對的類型碼不會影響宿主類的行為,可以使用Replace Type Code with Class (以類取代類型碼)來處理它們。但如果類型碼會影響宿主類的行為,那麼最後的辦法就是藉助多態來處理變化行為。 一般來說,這種情況的標誌就是像switch這樣的條件運算式。這種條件運算式可能有2種表現形式:switch語句或者if
Time of Update: 2018-12-07
從一個類中衍生出許多彼此相等的執行個體,希望將它們替換為一個對象。將這個值對象變成引用對象。動機:在許多系統中,都可以對對象做一個有用的分類:引用對象和值對象。要在引用對象和值對象之間做選擇有時並不容易。有時候,你會從一個簡單的值對象開始,在其中儲存少量不可修改的資料。而後,你可能會希望給這個對象加入一些可修改資料,並確保對任何一個對象的修改都能影響到所引用此對象的地方。這時候你就需要將這個對象變成引用對象。做法:1、使用 Replace Constructor with Factory
Time of Update: 2018-12-07
物件導向程式的一個最明顯特徵就是:少用switch或(case)語句。從本質上說,switch語句的問題在於重複。你常會發現switch語句散佈於不同地點。如果要為它添加一個新的case子句,就必須找到所有switch語句並修改它們。物件導向中的多態概念可為此帶來優雅的解決辦法。 大多數時候,一看到switch語句,就應該考慮以多態來替換它。問題是多態該出現在哪?switch語句常常根據類型碼進行選擇,你要的是“與該類型碼相關的函數或類”,所以應該使用 Extract
Time of Update: 2018-12-07
代碼對一個 參數賦值。以一個臨時變數取代該參數的位置。 int Discount(int inputVal, int quantity, int yearTodate) { if (inputVal > 50) { inputVal -= 2; } } int Discount(int inputVal, int quantity, int
Time of Update: 2018-12-07
你需要面對傳統編程環境中的記錄結構。為該記錄建立一個“啞”資料對象。動機:記錄型結構是許多編程環境的共同性質。有一些理由使它們被帶進物件導向程式之中:你可能面對的是一個遺留程式,也可能需要通過一個傳統API來與記錄結構交流,或是處理從資料庫讀出的記錄。這些時候你就有必要建立一個介面類,用以處理這些外來資料。最簡單的做法就是先建立一個看起來類似外部記錄的類,以便日後將某些欄位和函數搬移到這個類中。一個不太常見但非常令人注目的情況是:數組中的每個位置上的元素都有特定含義,這種情況下應該使用
Time of Update: 2018-12-07
若干客戶使用類介面中的同一子集,或者2個類的介面部分相同。將相同的子集提煉到一個獨立介面中。動機:類之間彼此互用的方式有若干種。“使用一個類”通常意味著用到該類的所有責任區。另一種情況是,某一組客戶只使用類責任區中的一個特定子集。再一種情況是,這個類需要與所有協助處理某些特定請求的類合作。 對於後2種情況,將真正用到的這部分責任分離出來通常很有意義,因為這樣可以使系統的用法更清晰,同時也更容易看清系統的責任劃分。如果新的類需要支援上述子集,也比較能夠看清子集內有些什麼東西。
Time of Update: 2018-12-07
你希望在建立對象時不僅僅是做簡單的建構動作。將建構函式替換為工廠函數。動機:就是在派生子類的過程中以工廠函數取代類型碼。你可能常常需要根據類型碼建立相應的對象,現在,建立名單中還得加上子類,那些子類也是根據類型碼來建立。然而由於建構函式只能返回單一類型的對象,因此你需要將建構函式替換為工廠函數。 此外,如果建構函式的功能不能滿足你的需要,也可以使用工廠函數代替它。工廠函數也是Change Value to Reference