2015-05-27 181 views
2

我需要重構現有的抽象類來實現依賴注入,但是這個類有兩個構造函數接受其他參數。構造函數注入,避免非依賴參數

public abstract class MyClassBase 
{ 
    MyClassBase(int settingId) 
    { 
     _settingId = settingId; 
    } 

    MyClassBase(Setting setting) 
    { 
     _setting = setting; 
    } 
    ... 
} 

我需要注入一些接口,並避免在構造函數中傳遞任何其他參數,如「settingId」和「Setting」。 所以我的想法是創建兩個方法來設置這些參數,一旦我們創建了這個類的實例。

public abstract class MyClassBase 
{ 
    private readonly IOneService _oneService; 
    private readonly ITwoService _twoService; 

    MyClassBase(IOneService oneService, ITwoService twoService) 
    { 
     _oneService = oneService; 
     _twoService = twoService; 
    } 

    protected void SetupSetting(int settingId) 
    { 
     _settingId = settingId; 
    } 

    protected void SetupSetting(Setting setting) 
    { 
     _setting = setting; 
    } 

    protected Setting Setting 
    { 
     get 
     { 
      if(_setting == null) 
      { 
       _setting = _oneService.getSettingById(_settingId); 
      } 

      return _setting; 
     } 
    } 
} 

但它看起來並不作爲一個妥善的解決辦法,因爲如果開發商忘了執行這些方法只是在創建實例後,我們可以得到一個異常一個(對象未設置爲引用...)的未來。 我應該如何正確地做到這一點?

+0

您的設置方法不正確,它不會返回任何內容。 –

回答

3

不可以。您應該從您的從屬界面獲取所有需要的數據。如:

MyClassBase(IOneService oneService, ITwoService twoService, ISettings set) 
{ 
    _setting = set; 
    .... 
} 
+0

+1,Setting實例可能應該直接注入或由其中一個注入服務提供。 – npace

+0

我同意你的觀點,儘管我不認爲增加一個'ISettings'抽象有什麼價值。看到我的答案。 – Steven

4

您的injectables應該只有一個構造函數。有multiple constructors is an anti-pattern。類需要運行的所有東西都必須通過構造函數傳入;使用多個步驟構建對象導致temporal coupling, which is a design smell

所以一般來說,我同意@ realnero的解決方案,儘管用接口抽象Settings對象可能沒有用處。接口是爲了抽象行爲,但是這樣的設置對象通常只包含數據,沒有行爲。因此添加抽象將不起作用。

雖然注入一個對象可以很好,但這樣的對象經常被濫用。你不應該把更多的東西傳遞給構造函數,而是直接需要它自己。如果Settings對象包含整個應用程序的值,那麼將不清楚此類所需的值。每次配置更改時,它也會導致您更改Settings對象,並且將會有許多消費者依賴於這個不斷增長的類別Settings

這些設置類通常用於分派到配置文件。換句話說,當消費者詢問類的值時,它會查詢配置文件。這會導致一個懶惰地讀取的配置文件。這使得應用程序在運行時很容易失敗,因爲配置文件中存在拼寫錯誤。相反,您希望應用程序在啓動時直接失敗(快速失敗)。

因此,您應該只注入此組件所需的配置值,並且應用程序啓動時應從配置文件中讀取這些值。這允許應用程序在配置不正確時快速失敗,使組件非常清楚需要什麼,並防止您在整個應用程序依賴的情況下擁有中央配置類。

但是具有依賴關係的基類本身就是代碼味道。沒有具體的例子,就不可能說出如何重構,但我認爲有兩個設計錯誤導致使用基類。

開發人員經常將交叉問題轉移到基類中。這將導致這些基類增長並變得難以維護,並且導致基類的複雜性與派生類交織在一起,使得它們變得複雜且難以測試。相反,應該使用裝飾或攔截來增加橫切關注點。裝飾設計模式在應用橫切關注方面非常有效。它允許服務根本沒有基類,並且在增加新的交叉問題時提供了很大的靈活性。以this article爲例,看看這個問題。

在殼體基類不處理橫切關注,但中央的應用程序邏輯的許多派生類重用,這抽象基類邏輯到一個單獨的服務通常是一個更好的方法。當這樣做時,這個新的服務可以被注入到你的組件中,這使得他們可以忽略這個新服務本身的依賴關係。它可以防止你必須傳遞基類的依賴並調用基類的構造函數。其中一種方法是使用Aggregate Services

+1

非常令人印象深刻的答案,非常感謝 – Sergey

相關問題