2017-10-16 66 views
1

我有默認DI實現的Asp.net Core項目。 因此,我通過DI獲取BL服務實例,存儲庫和EF上下文。 我有抽象方法返回某些類型的參數。如何將抽象方法重構爲DI

IDocumentPreprocessor CreateDocumentPreprocessor(DocType docType) 
    { 
     switch (docType) 
     { 
      case DocType.Txt: 
       return new TxtPreprocessor(_context, _docRepository); 
      case DocType.Doc: 
       return new DocPreprocessor(_docRepository); 

      default: 
       throw new ... 
     } 
    } 

我不喜歡這裏用「新」直接創建實例。 但我不確定是否有可能將此邏輯傳遞給DI。 所以這個問題 - 如何將其重構爲DI使用?

回答

3

將邏輯封裝在另一個DI注入服務中:IDocumentPreprocessorFactory。你在那裏注入工廠方法來實現IDocumentPreprocessor

public interface IDocumentPreprocessorFactory 
{ 
    IDocumentPreprocessor CreateDocumentPreprocessor(DocType docType); 
} 

public class DocumentPreprocessorFactory : IDocumentPreprocessorFactory 
{ 
    private readonly Func<TxtPreprocessor> createTxtPreprocessor; 

    private readonly Func<DocPreprocessor> createDocPreprocessor; 

    public DocumentPreprocessorFactory(
     Func<TxtPreprocessor> createTxtPreprocessor, 
     Func<DocPreprocessor> createDocPreprocessor) 
    { 
     this.createTxtPreprocessor = createTxtPreprocessor; 
     this.createDocPreprocessor = createDocPreprocessor; 
    } 

    public IDocumentPreprocessor CreateDocumentPreprocessor(DocType docType) 
    { 
     switch (docType) 
     { 
      case DocType.Txt: 
       return this.createTxtPreprocessor(); 
      case DocType.Doc: 
       return this.createDocPreprocessor(); 
      default: 
       throw new... 
     } 
    } 
} 

您現在必須使用工廠方法的註冊擴展您的DI設置。我沒有使用核心的DI,但我相信它會是這個樣子

services.AddSingleton<Func<DocPreprocessor>>(ctx =>() => ctx.GetService<DocPreprocessor()); 
services.AddSingleton<Func<TxtPreprocessor>>(ctx =>() => ctx.GetService<TxtPreprocessor()); 
+1

你可以用工廠類封裝這個函數如果OP想要一個新的DocType,比如DocType.Pdf, 'DocumentPreprocessorFactory'類中不需要更改嗎?儘管添加新類型是一個相當簡單的更改,但它是否違反了Open Closed原則來更改「DocumentPreprocessorFactory」類以包含用於添加Pdf功能的新邏輯?如果OP最終需要'DocType.Xml'等,那麼也一樣? – 2017-10-16 12:59:59

+0

@邁克 - 毛瑞爾,你說的沒錯。但是,重構OP的'switch'塊是開放式的,這是完全不同的故事。 –

+0

有趣。我很想知道是否有一個解決這個問題而不違反SOLID原則的實現。 – 2017-10-16 13:58:04

1

這可以幫助你..在任何註冊類

 // object lifetime transient or others.. determine according to your needs 
     services.AddTransient<TxtPreprocessor>(); 
     services.AddTransient<DocPreprocessor>(); 
     services.AddTransient(processorFactory => 
     { 
      Func<DocType, IDocumentPreprocessor> factoryFunc = docType => 
      { 
       switch (docType) 
       { 
        case DocType.Txt: 
         return processorFactory.GetService<TxtPreprocessor>(); 
        default: 
         return processorFactory.GetService<DocPreprocessor>();// DocPreprocessor is defult 
       } 
      }; 
      return factoryFunc; 
     }); 

使用..

public class AnyClass 
{ 
    private readonly IDocumentPreprocessor _documentProcessor; 

    public AnyClass(Func<DocType, IDocumentPreprocessor> factoryFunc) 
    { 
     _documentProcessor = factoryFunc(DocType.Doc); 
    } 
} 

如果你想