至于Product和ProductRepository的代碼就非常簡單了,這里不多解釋。
示例到這里,也許大家有個疑問:上面的代碼有些什么問題?
q ProductService依賴于ProductRepository。在沒有任何變化的情況下,這沒有什么問題。但是如果現在項目換了數據存儲設備,例如將數據庫換成了XML文件,或者數據庫的訪問技術從ADO.NET 換成了Entity Framework,那么ProductRepository的代碼就得改變,這會使得整個項目都需要重新編譯,重新部署。問題來了:此時系統中只有ProductRepository一個變化點,為什么非得要求整個項目重新編譯,重新部署呢?難道不能只重新編譯和部署那個變化的模塊呢?
q 代碼不具有測試性能。要想知道此段功能代碼是否按照了我們的意愿運行,可以通過人工審核,然后通過GUI界面獲取數據來進行調試,此時的邏輯相對而言比較簡單,此方法也還行得通。不過,一旦業務邏輯變得復雜或代碼量的劇增,那么很難確保代碼不會出錯,而這些錯誤很多時候只會在運行時才能被發現。
q 緩存機制依賴于HttpContext,這不僅僅會讓測試產生困難(盡管可以有Mock),而且會對后續系統的擴展有阻礙(例如采用分布式緩存)。
對以上的問題進行進一步分析,可以知道,這都是因為違背了以下設計原則:
q ProductService依賴了ProductRepository的具體實現,而ProductRepository是一個可能的變化點。也就是說:ProductService這個高層模塊依賴了ProductRepository底層模塊,違背了依賴倒置原則,這也就使得一個ProductRepository變化,整個項目都需要重新編譯,重新部署。同理,緩存機制也是。
q 對于可測試性的問題,嚴格來說,上面的代碼是可以測試的,但是測試的時候必須依賴于外部的數據存儲設備,例如數據庫,那么測試的結果可能會由于數據的變動而不一樣,而且每次測試所花的時間也會比較長。
接下來嘗試重構上面的代碼,讓代碼的組織方式更加的靈活和易于擴展。
既然上面代碼主要是違背了DIP依賴倒置原則(再次回顧一下DIP:依賴抽象,而不依賴具體實現)。
那么現在就提出接口IProductRepository,使得ProductService依賴這個接口,代碼如下: