返回總目錄 本小節目錄 Introduce Foreign Method(引入外加函數) Introduce Local Extension(引入本地擴展) Introduce Foreign Method(引入外加函數) Introduce Local Extension(引入本地擴展) 7Int ...
本小節目錄
7Introduce Foreign Method(引入外加函數)
概要
你需要為提供服務的類增加一個函數,但你無法修改這個類。
在客戶類中建立一個函數,並以第一參數形式傳入一個服務類實例。
動機
好吧,我得不得說這個在C#中稱為:擴展函數。這個其實也沒什麼好說的,這種事情發生過太多次了。假說你正在使用string類,它基本上提供了我們所需要的功能。但是,你正在做一項新服務,string類中恰巧無法提供。這時候你是不是想修改string的源代碼,將這個功能加上。很可惜我們不能這麼做,但是C#允許我們新建擴展函數。
範例
假如說,我們程式大量使用Dictionary<string,string>,我們要獲得某個字典的value,可以這樣做:
var dictionary = new Dictionary<string, string>(); string result; dictionary.TryGetValue("key", out result);
但是我們每次都得定義一個out參數,這樣很不方便。於是乎,我們建立一個擴展函數,至於怎麼新建擴展函數,請自行百度。
public static class DictionaryExt { public static string TryGetValue(this Dictionary<string, string> thisObj, string key) { if (thisObj == null || !thisObj.ContainsKey(key)) return null; return thisObj[key] ?? ""; } }
這樣一來,我們在使用的時候,就可以這樣:
var dictionary = new Dictionary<string, string>(); var res = dictionary.TryGetValue("key");
這樣一來大大提高了我們的效率。
小結
如果客戶類只是用這項功能一次,那麼額外編碼工作沒什麼大不了,甚至可能根本不需要原本提供服務的那個類。然而,如果你需要多次使用這個函數,就得不斷重覆這些代碼。
重覆代碼是軟體萬惡之源,重覆代碼應該被抽出來放進同一個函數中。
8Introduce Local Extension(引入本地擴展)
概要
你需要為提供服務的類提供一些額外函數,但你無法修改這個類。
建立一個新類,使它包含這些額外函數。讓這個擴展品成為源類的子類。
動機
類的作者無法預知未來,他們常常沒能為你預先準備一些有用的函數。如果只需要一兩個函數,可以使用Introduce Foreign Method。但是如果需要的額外函數超過兩個,外加函數就很難控制它們了。所以將這些函數組織在一起,讓其成為源類的子類。這個子類稱為本地擴展。
範例
我們還是以Dictionary<string,string>這個為例。
首先新建一個DictionaryString,讓其成為Dictionary<string,string>的子類。
class DictionaryString : Dictionary<string, string> { }
然後在擴展類中添加新特性,並使用Move Method將所有外加函數搬移到擴展類。
class DictionaryString : Dictionary<string, string> { public string TryGetValue(Dictionary<string, string> thisObj, string key) { if (thisObj == null || !thisObj.ContainsKey(key)) return null; return thisObj[key] ?? ""; } //other methods... }
使用方法和上個手法一樣:
DictionaryString dic=new DictionaryString(); dic.TryGetValue("key");
小結
使用本地擴展讓我們堅持了“函數和數據應該被統一封裝”的原則。如果一直把本該放在擴展類中的代碼零散地放置於其他類中,最終只會讓其他這些類變得過分複雜,並使得其中函數難以被覆用。
階段性小結
在對象的設計過程中,“決定把責任放在哪兒”即使不是最重要的事,也是最重要的事之一。我們可能一開始並不能保證自己做對。但是我們可以使用Move Field和Move Method簡單地移動對象行為,就可以解決這些問題。
類往往會因為承擔過多責任而變得臃腫不堪。這時候可以使用Extract Class將一部分責任分離出去。如果一個類變得太“不負責任”,就使用Inline Class將它融入另一個類。如果一個類使用了另一個類,運用Hide Delegate將這種關係隱藏起來。有時候隱藏委托類會導致擁有者的介面經常變化,此時需要使用Remove Middle Man。
當不能訪問某個類的源碼,又想把責任移進這個不可修改的類時,要使用Introduce Foreign Method和Introduce Local Extension。如果加入的是一或兩個函數,就會使用Introduce Foreign Method;如果不止一兩個函數,就要使用Introduce Local Extension。
To Be Continued……