- Live軟件開發面面談
- 潘俊編著
- 1101字
- 2019-07-30 17:55:00
1.4 真的實現了嗎
工廠、服務定位器和依賴注入是通常人們用于消除模塊間依賴的三大法寶。在檢視這些模式的代碼時,不知道聰明的讀者有沒有產生一個疑問:播放器對編解碼器的依賴真的消除了嗎?
1.4.1 依賴的傳遞性
?a, b, c∈X: (aRb∧bRc)?aRc
相信很多朋友對上面表達式中符號的含義還有印象,它是傳遞關系(Transitive relation)的數學定義。一個集合X上的二元關系R被稱為是傳遞的,如果集合中任意元素a對b有此關系,而b對c又有此關系時,a對c就有此關系。我們都知道很多這樣的關系,例如有序關系:如果a>b,b>c,就有a>c。程序中對象間的依賴也是一種傳遞關系。如果對象a依賴對象b,b又依賴c,那么a對c也有依賴。
再來看上一節的三種模式。播放器的代碼中都沒有對編解碼器具體類型的依賴。但是,在工廠模式中,工廠創建了具體編解碼器的實例;在服務定位器模式中,負責注冊服務的控制器創建了具體編解碼器的實例;在依賴注入模式中,負責注入的控制器創建了具體編解碼器的實例。也就是說,三種模式下仍然有某個對象依賴具體編解碼器。在工廠模式中,播放器依賴工廠;在服務定位器模式中,控制器依賴播放器;在依賴注入模式中,控制器依賴播放器。因為依賴有傳遞性,所以在工廠模式下,播放器依然依賴具體編解碼器。在后兩種模式下,播放器雖然不依賴播放器了,但是控制器和播放器一起都屬于對編解碼器模塊的調用模塊,將播放器的依賴轉移到控制器,并沒有解決問題。所以結論就是工廠、服務定位器和依賴注入模式并沒有消除模塊間的依賴。有人或許會質疑,我上面的代碼寫得不夠好,但是它們的確體現了三種模式的內涵,這是毫無疑問的。
1.4.2 依賴的形式
既然沒有消除依賴,就要繼續想辦法。調用方的代碼不能引用具體的編解碼器類型,但總歸要以某種形式知道這些類型。用這些類型的名稱似乎是個不錯的方案,字符串記錄的名稱無須引用對應的類型,使用反射創建這些類型的實例,將調用者對被調用者的類型依賴從編譯時移除,而僅出現在運行時。編解碼器的類型名稱可以和之前的媒體文件類型名稱一樣,由播放器傳遞給工廠或服務定位器。不過依據這些名稱利用反射創建編解碼器實例的代碼太簡單,不如直接寫在播放器內。

與編解碼器的類型名稱一起出現的還有它所在的程序集的名稱,如果是Java,此名稱就會以Java包的信息形式被包裝在某個ClassLoader里。
然后再認真想想,這下真的消除了依賴嗎?消除依賴的本質是調用者和被調用者在都不知道對方具體實現的狀態下通過接口來合作。換言之,除了接口,雙方對對方一無所知。調用者不能引用被調用者的具體類型,就能知道這些類型的名稱嗎?
依賴的形式不僅包括直接使用被調用者的具體類型,還包括使用被調用者接口之外的任何信息。
所以,上述播放器依然依賴具體的編解碼器。