簡體   English   中英

如何將依賴項注入應用於抽象工廠

[英]How do I apply dependency injection to an abstract factory

我剛剛讀完Mark Seemann 在.NET中依賴注入,現在正在嘗試重構一些舊代碼。 (在此階段,我不依賴任何特定的DI容器,而只是嘗試將所有依賴項移至一個位置)。

我正在看下面的工廠類,該類通過使用archiveReader.GetArchiveType()讀取歸檔文件的前幾個字節來確定ArchiveType ,然后根據ArchiveType枚舉返回ArchiveRestorer的實例。

public class ArchiveRestorerFactory : IArchiveRestorerFactory
{
    public ArchiveRestorer Create(ArchiveReader archiveReader)
    {
        ArchiveType type = archiveReader.GetArchiveType();
        switch (type)
        {
            case ArchiveType.CurrentData:
                return new CurrentDataArchiveRestorer(archiveReader);
                break;
            case ArchiveType.HistoricalData:
                return new HistoricalDataArchiveRestorer(archiveReader);
                break;
            case ArchiveType.AuditTrail:
                return new AuditTrailArchiveRestorer(archiveReader);
                break;
            default:
                throw new Exception("ArchiveRestorerFactory error: Unknown value for ArchiveType.");
        }
    }
}

我如何重構它,以便類不依賴於具體類型CurrentDataArchiveRestorerHistoricalDataArchiveRestorerAuditTrailArchiveRestorer

我應該將這三個混凝土修復劑搬到工廠的建築商里嗎?

public ArchiveRestorer Create(ArchiveReader archiveReader, 
    ArchiveRestorer currentDataArchiveRestorer, 
    ArchiveRestorer historicalDataArchiveRestorer, 
    ArchiveRestorer auditTrailDataArchiveRestorer)
{
    // guard clauses...
    // assign to readonly fields
}

這似乎是這里建議的方法,但是當僅需要一個還原器時,它將實例化所有三個還原器嗎? 如果我有20種可能的具體實現呢?

我覺得我應該為每種類型的還原器實現一個具體的工廠,並將其返回,但是我只是將一個new替換為另一個。

重構它的最佳方法是什么?

給定您已經獲得的代碼,我執行此操作的方式將是為每個具有Create()方法的對象創建一個工廠。

我還要為這些工廠提供接口,並讓它們從常規工廠接口繼承。

然后,您可以將接口用作注入到構造函數中的點。

類似於以下內容:

case ArchiveType.CurrentData:
                return _currentDateArchiveRestorerFactory.Create(archiveReader);
                break;

另外,最好有一個工廠來創建給定類型的實例。 由於所有這些對象都是還原器,因此您可以僅基於enum而不是switch創建實例。

_restorerFactory.Create(ArchiveType.CurrentData);

為什么不讓ArchiveReader負責創建適當的ArchiveRestorer? 然后,代碼的第一次迭代將如下所示:

public class ArchiveRestorerFactory : IArchiveRestorerFactory
{
    public ArchiveRestorer Create(ArchiveReader archiveReader)
    {
        ArchiveRestorer restorer = archiveReader.GetArchiveRestorer();
        return restorer;
    }
}

到那時,工廠將很明顯是多余的,因此在代碼的第二次迭代中,您可以丟棄它,讓使用者直接調用ArchiveReader。

使用一個具有該接口的返回類型的方法來創建一個接口,並讓三個存檔器類實現該接口,然后在create方法中,參數類型將僅為該接口,並且它將通過調用剛創建的接口方法來返回所需的對象。 因此,您無需在create方法中使用具體類型。

我將通過同意一個命名約定並利用Unity的命名功能來解決這個問題。 此處的示例: https : //dannyvanderkraan.wordpress.com/2015/06/29/real-world-example-of-dependency-injection-based-on-run-time-values/

interface ILogger
{
    void Log(string data);
}

class Logger : ILogger
{
    .
    .
    .
}

此時,您可以使用中間工廠對象來返回要在組件中使用的記錄器:

class MyComponent
{
  void DoSomeWork()
  {
    // Get an instance of the logger
    ILogger logger = Helpers.GetLogger();
    // Get data to log
    string data = GetData();

    // Log
    logger.Log(data);
  }
}

class Helpers
{
  public static ILogger GetLogger()
  {
    // Here, use any sophisticated logic you like
    // to determine the right logger to instantiate.

    ILogger logger = null;
    if (UseDatabaseLogger)
    {
        logger = new DatabaseLogger();
    }
    else
    {
        logger = new FileLogger();
    }
    return logger;
  }
}
class FileLogger : ILogger
{
    .
    .
    .
}

class DatabaseLogger : ILogger
{
    .
    .
    .
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM