Agile Principles, Patterns, and Practices in C# 無瑕的程式碼 敏捷完整篇 第12章 ISP:介面隔離原則
第十二章內容是ISP:介面隔離原則,看範例可以比較快了解ISP。
ISP (The Interface Segregation Principle) : 介面隔離原則
不應該強迫客戶程式依賴它們未使用的方法。
如果強迫客戶程式依賴它們不使用的方法,客戶程式會面臨「未使用方法變更」而帶來變更,因此希望隔離介面。
介面污染
參考Listing 12-1與Listing 12-2 ,要做一個安全門超時會通知的專案。
圖12-1是常見的解決方案。
Door類別依賴TimerClient,然而並不是所有的Door都需要定時功能,所有衍生類別必須提供TimeOut方法的退化實作,有可能違反LSP。
Door衍生類別不使用TimerClient類別,也必須要import 它,產生不必要的複雜性與不必要的重複。
為了增加新功能基底類別一直新增新的方法,會讓介面變胖。
分離客戶就是分離介面
使用者迫使介面改變,Door介面與TimerClient介面是兩群不同的使用者,既然客戶程式分離,介面也應該分離。
TimerClient有修改也會影響到Door與Door所有客戶程式。
類別介面與物件介面
如何讓兩個分離的介面在同一個物件中實作,才能遵守ISP? 物件不必透過物件的介面存取,可透過委託或物件的基底類別存取。
使用委託來分離介面
參考圖12-2與 Listing12-4 ,建立一個衍生自TimerClient的物件,並把物件的請求委託給TimedDoor。
這種方法遵循ISP,並且避免Door與Timer之間的耦合。
缺點是想要註冊一個超時請求時,都要去建立一個新物件。委託會花費一些執行時間與記憶體。
使用多重繼承來分離介面
參考圖12-3與 Listing12-5 ,利用多重繼承來遵循ISP原則。TimedDoor同時繼承Door和TimerClient。
作者建議優先使用這個方案。
ATM使用者介面的例子
圖12-5是未改良前的結構,若是要新增PayGasBillTransaction,必須要改動UI介面,也會影響到其他功能的程式。
圖12-6是改良後的結構,作者採用多重繼承來分離介面。
檢查圖12-6,為了達到Listing12-7介面初始化,建構每個事務的時候得到特定的UI版本。C#中會把所有UI放到一個單一類別如Listing12-8。 UIGlobals類別把我們千辛萬苦分開的介面又結合在一起。
函數g想要存取DepositUI又要存取TransferUI,用兩個參數的寫法較佳
void g(DepositUI depositUI, TransferUI transferUI)
之後???????????????????? Listing12-9這段內容看不太懂
總結
過胖的類別會讓客戶程式之間產生不正常且有害的耦合關係。
客戶程式應僅僅依賴於它們實際呼叫的方法。
可使用多重繼承來分離介面
留言
張貼留言