2010-07-16 278 views
3

我正在與一個只有靜態函數的API進行交互,但無法打開和更改。包裝API以支持依賴注入

public class WindowsNativeGraphAPI 
    { 
     public static IEnumerable<IGraphData> GetGraphData(); 
     public static bool DeleteGraphData(IGraphData data); 
    } 

我希望能夠將API傳遞到一個函數或構造,並遵守依賴注入(以防萬一,我們後來換出API)。

public void GatherGraphData(IGraphAPI api) 
{...} 

爲了讓這個API作爲參數傳入,我至少需要使用接口傳遞給函數。

public interface IGraphAPI 
    { 
     IEnumerable<IGraphData> GetGraphData(); 
     bool DeleteGraphData(IGraphData data); 
    } 

但是,我需要在另一個類中實現接口,因爲我無法更改原始API。這個類將是一個API的輕量級包裝器,它只調用API上的相應函數並返回相同的結果。

public class WindowsGraphAPI : IGraphAPI 
    { 
     public IEnumerable<IGraphData> GetGraphData() 
     { 
      return WindowsNativeGraphAPI.GetGraphData(); 
     } 

     public bool DeleteGraphData(IGraphData data) 
     { 
      return WindowsNativeGraphAPI.DeleteGraphData(data) 
     } 
    } 

我不喜歡創建另一個類來包裝API的想法。我明白,這個包裝將是非常輕量級的,只會返回API的結果,但我如何測試包裝?包裝應該可能還包含一些異常處理來處理API中的錯誤。如果我們改用另一個API,那會遇到同樣的問題,我們不得不再次創建這些額外的類和接口。

理想情況下,最終結果將是一個可模擬的API,可以在爲使用它的新組件編寫單元測試時使用。

這是正確的方法嗎?它可以以另一種方式完成嗎?

謝謝

回答

6

是的,這是正確的方法。新的API接口和代理類封裝了使用什麼底層庫的決定 - 一個責任。

+0

+1 ASP.NET MVC廣泛地實現了這一功能,因此它提供了一組演示此方法的示例。 – 2010-07-16 13:10:15

0

是的,這是正確的方法。我不會把異常處理放在你的包裝器中,你所做的只是創建一個調用靜態方法的類,以便你可以使用DI。您希望包裝器在與靜態方法相同的情況下使用相同的情況下導致相同的異常。這樣,你可以在你的方法中使用相同的異常處理,就像你用靜態方法調用類一樣。然後,您可以在相同的情況下在您的模擬api類中拋出相同的異常並測試excation處理。

+2

我不能同意這些關於例外的陳述。異常是API的功能合同的一部分。如果由適配的API拋出的異常類型在包含適配的API本身的包中定義,那麼允許這些異常通過將允許實現細節通過抽象泄漏。最好將它們封裝在與接口一起定義的異常中。 – 2010-07-16 13:09:14

+2

從學術角度來看,這聽起來很棒,但在實踐中,您最終會在抽象異常中得到不完善的細節,這些細節會在實時代碼中調試問題,或者您必須執行大量工作來創建複雜的異常處理提供足夠的細節以便稍後調試,僅僅是爲了說明在某些情況下您可能完全改變實現而不是僅僅嘲笑windows API進行單元測試的事實。 – 2010-07-16 13:25:17

+1

我並不是說包裝器必須包裝由適配的API拋出的異常。我所說的是,客戶*不能*依賴於適配的API定義的異常類型,因爲這會形成緊密的耦合。 DI遠不止可測性。 – 2010-07-16 13:39:23