一切都使用工厂?
Using factory for everything?
我的软件应该控制一个或多个设备。程序流程就像它会在所有可用接口上搜索设备,并为每个找到的设备实例化一个 IDevice
类型的对象。在这里声明一下,所有这些对象都必须在运行时设置。
使用 Autofac 获得依赖倒置 (DI) 一切都必须在开始时设置。如果在运行时要使用某些东西,“工厂”就是要使用的东西。那么让我们深入研究一个例子:
程序启动如下所示:
class Program
{
static void Main(string[] args)
{
var container = ContainerConfig.Configure();
using (var scope = container.BeginLifetimeScope())
{
var app = scope.Resolve<IApplication>();
app.Run();
}
}
}
一旦“应用程序”得到解决,开始时已知的一切都已设置好。然后应用程序开始 (app.Run()
),搜索设备,然后设置找到的所有设备的列表。现在设置设备需要一堆“工厂”,基本上(这就是问题所在)“每个工厂一个 class”,通过“设备”实例化。
class Application : IApplication
{
readonly Device.Factory _deviceFactory;
readonly Log.Factory _logFactory;
readonly DateTime.Factory _dateTimeFactory;
readonly Incident.Factory _incidentFactory;
public Application(Device.Factory deviceFactory, Log.Factory logFactory, DateTime.Factory dateTimeFactory, Incident.Factory incidentFactory)
{
_deviceFactory = deviceFactory;
_logFactory = logFactory;
_dateTimeFactory = dateTimeFactory;
_incidentFactory = incidentFactory;
}
public void Run()
{
List<string> listOfDeviceIds = SearchAllDevices();
List<IDevice> listOfDevices = new List<IDevice>;
foreach(string deviceId in listOfDeviceIds)
{
listOfDevices.Add(deviceFactory(_logFactory, _dateTimeFactory, incidentFactory);
}
}
}
一个“设备”包含一个跟踪某事的记录器,在这个例子中它将记录一个时间和一个事件。所以一旦建立新的日志,就需要注入几个工厂。
public class Device : IDevice
{
public delegate Device Factory(Log.Factory logFactory, DateTime.Factory dateTimeFactory, Incident.Factory incidentFactory);
readonly DateTime.Factory _dateTimeFactory;
readonly Incident.Factory _incidentFactory;
readonly Log.Factory _logFactory;
List<Log> ListOfLogs = new List<Log>();
public Device(Log.Factory logFactory, DateTime.Factory dateTimeFactory, Incident.Factory incidentFactory)
{
_dateTimeFactory = dateTimeFactory;
_incidentFactory = incidentFactory;
_logFactory = logFactory;
}
public AddLog()
{
ListOfLogs().Add(_logFactory(_dateTimeFactory(), _incidentFactory() ));
}
}
public class Log()
{
public delegate Log Factory();
public IDateTime DateTime() { get; }
public IIncident Incident() { get; }
public Log(IDateTime dateTime, IIncident incident)
{
DateTime = dateTime;
Indicent = incident;
}
}
public DateTime : IDateTime
{
public delegate DateTime Factory();
//...
}
public Indicent : IIndicent
{
public delegate Indicent Factory();
//...
}
现在,这只是对设备的一点了解 class,它实际上集成了更多的东西。这就是它现在又变得凌乱了。
我在实例化“设备”时设置了大约 30 个子classes 甚至更多。因此,因为它们是在运行时设置的,所以它们都需要一个必须通过其构造函数“设备”提供的“工厂”。好吧,我想你明白了。
你是怎么处理的?还是我又走错了路?我是否通过试图反转对一切的依赖而误解了什么?
还有一点,就是整个故事要做到可测,interface和autofac是关键词。但是当使用工厂时,我总是必须使用它自己的 class 并且不能使用它的接口作为参考,此时 DI 不再实现。 ...?
public class MyClass : IMyClass
{
public delegate MyClass Factory();
// ...
}
使用它需要 MyClass.Factory
而不是 IMyClass.Factory
:
class Main()
{
MyClass.Factory _myClassFactory;
Main(MyClass.Factory myClassFactory)
{
_myClassFactory = myClassFactory;
}
foo ()
{
IMyClass myInstance = myClassFactory();
}
}
为什么没有人告诉我! ... ;-)
(好的,上面评论中提供的链接最终将我带到了这里)
总结
使用 Func<>
代替 delegates
和 .Factory
。这是我最大的误会。
重构代码
程序开始保持不变:
class Program
{
static void Main(string[] args)
{
var container = ContainerConfig.Configure();
using (var scope = container.BeginLifetimeScope())
{
var app = scope.Resolve<IApplication>();
app.Run();
}
}
}
但是然后:删除所有 delegates
,删除所有 .Factory
s 并且只在那个非常 [=37= 中使用的构造函数中添加依赖项(如 Func<>
) ] (当然,我怎么可能)。然后一个人会得到这个:
class Application : IApplication
{
readonly Func<IIDevice> _deviceFactory;
public Application(Func<IDevice> deviceFactory)
{
_deviceFactory = deviceFactory;
}
public void Run()
{
List<string> listOfDeviceIds = SearchAllDevices();
List<IDevice> listOfDevices = new List<IDevice>;
foreach(string deviceId in listOfDeviceIds)
{
listOfDevices.Add(deviceFactory();
}
}
}
以及在运行时实例化的内容:
public class Device : IDevice
{
readonly Func<ILog> _logFactory;
List<Log> ListOfLogs = new List<Log>();
public Device(Log.Factory logFactory)
{
_logFactory = logFactory;
}
public AddLog()
{
ListOfLogs().Add(_logFactory());
}
}
public class Log()
{
public IDateTime DateTime() { get; }
public IIncident Incident() { get; }
public Log(Func<IDateTime> dateTimeFactory, Func<IIncident> )
{
DateTime = dateTimeFactory();
Indicent = incidentFactory();
}
}
public DateTime : IDateTime
{
//...
}
public Indicent : IIndicent
{
//...
}
我的软件应该控制一个或多个设备。程序流程就像它会在所有可用接口上搜索设备,并为每个找到的设备实例化一个 IDevice
类型的对象。在这里声明一下,所有这些对象都必须在运行时设置。
使用 Autofac 获得依赖倒置 (DI) 一切都必须在开始时设置。如果在运行时要使用某些东西,“工厂”就是要使用的东西。那么让我们深入研究一个例子:
程序启动如下所示:
class Program
{
static void Main(string[] args)
{
var container = ContainerConfig.Configure();
using (var scope = container.BeginLifetimeScope())
{
var app = scope.Resolve<IApplication>();
app.Run();
}
}
}
一旦“应用程序”得到解决,开始时已知的一切都已设置好。然后应用程序开始 (app.Run()
),搜索设备,然后设置找到的所有设备的列表。现在设置设备需要一堆“工厂”,基本上(这就是问题所在)“每个工厂一个 class”,通过“设备”实例化。
class Application : IApplication
{
readonly Device.Factory _deviceFactory;
readonly Log.Factory _logFactory;
readonly DateTime.Factory _dateTimeFactory;
readonly Incident.Factory _incidentFactory;
public Application(Device.Factory deviceFactory, Log.Factory logFactory, DateTime.Factory dateTimeFactory, Incident.Factory incidentFactory)
{
_deviceFactory = deviceFactory;
_logFactory = logFactory;
_dateTimeFactory = dateTimeFactory;
_incidentFactory = incidentFactory;
}
public void Run()
{
List<string> listOfDeviceIds = SearchAllDevices();
List<IDevice> listOfDevices = new List<IDevice>;
foreach(string deviceId in listOfDeviceIds)
{
listOfDevices.Add(deviceFactory(_logFactory, _dateTimeFactory, incidentFactory);
}
}
}
一个“设备”包含一个跟踪某事的记录器,在这个例子中它将记录一个时间和一个事件。所以一旦建立新的日志,就需要注入几个工厂。
public class Device : IDevice
{
public delegate Device Factory(Log.Factory logFactory, DateTime.Factory dateTimeFactory, Incident.Factory incidentFactory);
readonly DateTime.Factory _dateTimeFactory;
readonly Incident.Factory _incidentFactory;
readonly Log.Factory _logFactory;
List<Log> ListOfLogs = new List<Log>();
public Device(Log.Factory logFactory, DateTime.Factory dateTimeFactory, Incident.Factory incidentFactory)
{
_dateTimeFactory = dateTimeFactory;
_incidentFactory = incidentFactory;
_logFactory = logFactory;
}
public AddLog()
{
ListOfLogs().Add(_logFactory(_dateTimeFactory(), _incidentFactory() ));
}
}
public class Log()
{
public delegate Log Factory();
public IDateTime DateTime() { get; }
public IIncident Incident() { get; }
public Log(IDateTime dateTime, IIncident incident)
{
DateTime = dateTime;
Indicent = incident;
}
}
public DateTime : IDateTime
{
public delegate DateTime Factory();
//...
}
public Indicent : IIndicent
{
public delegate Indicent Factory();
//...
}
现在,这只是对设备的一点了解 class,它实际上集成了更多的东西。这就是它现在又变得凌乱了。
我在实例化“设备”时设置了大约 30 个子classes 甚至更多。因此,因为它们是在运行时设置的,所以它们都需要一个必须通过其构造函数“设备”提供的“工厂”。好吧,我想你明白了。
你是怎么处理的?还是我又走错了路?我是否通过试图反转对一切的依赖而误解了什么?
还有一点,就是整个故事要做到可测,interface和autofac是关键词。但是当使用工厂时,我总是必须使用它自己的 class 并且不能使用它的接口作为参考,此时 DI 不再实现。 ...?
public class MyClass : IMyClass
{
public delegate MyClass Factory();
// ...
}
使用它需要 MyClass.Factory
而不是 IMyClass.Factory
:
class Main()
{
MyClass.Factory _myClassFactory;
Main(MyClass.Factory myClassFactory)
{
_myClassFactory = myClassFactory;
}
foo ()
{
IMyClass myInstance = myClassFactory();
}
}
为什么没有人告诉我! ... ;-) (好的,上面评论中提供的链接最终将我带到了这里)
总结
使用 Func<>
代替 delegates
和 .Factory
。这是我最大的误会。
重构代码
程序开始保持不变:
class Program
{
static void Main(string[] args)
{
var container = ContainerConfig.Configure();
using (var scope = container.BeginLifetimeScope())
{
var app = scope.Resolve<IApplication>();
app.Run();
}
}
}
但是然后:删除所有 delegates
,删除所有 .Factory
s 并且只在那个非常 [=37= 中使用的构造函数中添加依赖项(如 Func<>
) ] (当然,我怎么可能)。然后一个人会得到这个:
class Application : IApplication
{
readonly Func<IIDevice> _deviceFactory;
public Application(Func<IDevice> deviceFactory)
{
_deviceFactory = deviceFactory;
}
public void Run()
{
List<string> listOfDeviceIds = SearchAllDevices();
List<IDevice> listOfDevices = new List<IDevice>;
foreach(string deviceId in listOfDeviceIds)
{
listOfDevices.Add(deviceFactory();
}
}
}
以及在运行时实例化的内容:
public class Device : IDevice
{
readonly Func<ILog> _logFactory;
List<Log> ListOfLogs = new List<Log>();
public Device(Log.Factory logFactory)
{
_logFactory = logFactory;
}
public AddLog()
{
ListOfLogs().Add(_logFactory());
}
}
public class Log()
{
public IDateTime DateTime() { get; }
public IIncident Incident() { get; }
public Log(Func<IDateTime> dateTimeFactory, Func<IIncident> )
{
DateTime = dateTimeFactory();
Indicent = incidentFactory();
}
}
public DateTime : IDateTime
{
//...
}
public Indicent : IIndicent
{
//...
}