[英]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.");
}
}
}
我如何重構它,以便類不依賴於具體類型CurrentDataArchiveRestorer
, HistoricalDataArchiveRestorer
和AuditTrailArchiveRestorer
?
我應該將這三個混凝土修復劑搬到工廠的建築商里嗎?
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.