2013-05-21 250 views
2

我有一個通用類,我們稱之爲MyClass<T>,它需要一個工廠方法,以便從客戶端代碼抽象構造函數細節。泛型類或非泛型類的靜態工廠方法?

這兩個選項中的哪一個是正確的? (包括例如實例化代碼)

  1. 靜態非通用工廠上的原始通用MyClass<T>方法:

    MyClass<SomeType> instance = MyClass<SomeType>.CreateNew(); 
    
  2. 靜態通用工廠方法上的專用, 非通用靜態MyClass實現塔季翁:

    MyClass<SomeType> instance = MyClass.CreateNew<SomeType>(); 
    
+0

我認爲這個問題是一個很好的人選[你最有爭議的編程觀點是什麼?](http://stackoverflow.com/questions/406760/whats-your-most-controversial-programming-opinion),但只適用於C#語言 –

回答

1

在乍一看,貌似正確回答你的問題是#1。這是因爲你的班級是MyClass<T>,因此工廠也應該是T特定的。但還有更多的東西比這個簡單的答案。

在繼續之前,我會添加第三種可能性:非靜態工廠類。依賴於工廠的對象會擁有一個公共屬性,通過它可以接收工廠對象。如果沒有其他實例被分配,屬性的Getter將實例化默認工廠。這允許以後依賴注入,並且還有助於編寫依賴於他們自己的假工廠的單元測試。解決方案會是這個樣子(忽略了片刻仿製藥):

public class ISomeFactory { ... } 

public class DefaultSomeFactory: ISomeFactory { ... } 

public class ClientClass 
{ 
    public ISomeFactory FactoryOfSome // Right place for dependency injection 
    { 
     get 
     { 
      if (_fact == null) 
       _fact = new DefaultFactory(); 
      return _fact; 
     } 
     set { _fact = value; } 
    } 
    private ISomeFactory _fact; 
} 

現在,就像我說的,你們班去與通用參數MyClass<T>然後工廠應與泛型參數去還有:Factory<T>。這個解決方案比一般工廠的通用方法更好,只是因爲創建一個實例可能是特定於T。與一般的工廠解決方案可以讓你:

public class SpecialSomeFactory: DefaultSomeFactory<string> { ... } 

通過這種方式,可以覆蓋現有的工廠類的行爲,並以另一種方式產生的特殊字符串實例。這很重要,因爲處理字符串通常與處理諸如int或double的基本類型大不相同。有機會專業化工廠可能是有益的。但是現在你明白爲什麼有一個靜態工廠可能是一個壞主意 - 靜態不能被擴展。

+1

許多有經驗的測試單位經驗的開發人員都知道這兩個選項都不好:)。恕我直言,最好做構造函數注入而不是懶得到,因爲它更容易模擬和防止'魔術依賴'。 +1 btw。 – Fendy

+0

@芬迪 - 你是對的構造函數。我遵循的一般規則是爲必需參數使用構造函數注入,爲可選參數使用屬性注入。懶得到經常被濫用。我只用它作爲財產重寫的模式。在上面的例子中,屬性具有一般不應該被改變的默認實現。只有一段時間(例如在單元測試中),您將使用不同的實現來更改它。訣竅是在這個問題:改變一個屬性值會打破代碼? YES意味着你對它進行硬編碼; NO表示IoC容器是正確的方式。 –

+1

如果「更改屬性值將破壞代碼」意味着您需要修復實現,而不是硬編碼默認值。我認爲'Lazy'屬性的缺點是,如果需要更改(DefaultFactory),那麼你必須在每個地方都做。不要擔心,它可能不適用於這個(你)的情況,但可以在其他情況下發生。代碼濫用很容易 – Fendy

1

這兩個示例本質上都是服務定位器模式的變體。有爭議的是,這通常被認爲是反模式,因爲使用它的類的依賴關係對其消費者是不可見的。

使您的依賴更加明確的一種方法是採用類似於第一個示例的解決方案,但使CreateNew()成爲實例方法,而不是靜態方法。