我刚刚完成了Mark Seemann的书 .NET中的依赖注入,现在我正在尝试重构一些遗留代码。 (在此阶段,我不依赖于任何特定的DI容器,而只是尝试将所有依赖项移动到一个位置。)
我正在查看以下工厂类,它通过使用ArchiveType
读取存档的前几个字节来确定archiveReader.GetArchiveType()
,然后基于此返回ArchiveRestorer
的实例ArchiveType
枚举。
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
}
这似乎是建议here的方法,但是当只需要一个时,它会实例化所有三个恢复器?如果我有20种不同的具体实现呢?
我觉得我应该为每种类型的恢复器实现一个具体的工厂并返回它,但之后我只是将一个new
替换为另一个。{/ p>
重构这个的最佳方法是什么?
答案 0 :(得分:2)
考虑到你已经获得的代码,我这样做的方法是为每个具有Create()
方法的对象创建一个工厂。
我也有这些工厂的接口,并让它们从一般的工厂接口继承。
然后,您可以使用接口作为注入构造函数的点。
这将被称为类似于此:
case ArchiveType.CurrentData:
return _currentDateArchiveRestorerFactory.Create(archiveReader);
break;
或者,拥有一个创建给定类型实例的工厂可能会更好。由于所有这些对象都是还原器,因此您只需基于enum
而不是switch
创建实例。
_restorerFactory.Create(ArchiveType.CurrentData);
答案 1 :(得分:2)
为什么不让ArchiveReader负责创建适当的ArchiveRestorer?然后代码的第一次迭代看起来像这样:
public class ArchiveRestorerFactory : IArchiveRestorerFactory
{
public ArchiveRestorer Create(ArchiveReader archiveReader)
{
ArchiveRestorer restorer = archiveReader.GetArchiveRestorer();
return restorer;
}
}
到那时,应该很明显工厂是多余的,所以在代码的第二次迭代中你可以抛弃它让消费者直接调用ArchiveReader。
答案 2 :(得分:1)
使用一个返回类型为该接口的方法创建一个接口,让三个归档类实现该接口,然后在create方法中,参数类型只是接口,它将通过调用接口方法返回所需的对象你刚刚创建。所以你在create方法中不需要具体的类型。
答案 3 :(得分:0)
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
{
.
.
.
}
答案 4 :(得分:0)
我会通过同意命名约定并利用Unity的命名注册能力来解决这个问题。此示例如下:https://dannyvanderkraan.wordpress.com/2015/06/29/real-world-example-of-dependency-injection-based-on-run-time-values/