一切都使用工厂?

问题描述

我的软件将控制一个或多个设备。程序流程就像它将搜索所有可用接口上的设备,并为找到的每个设备实例化 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 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,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,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();
    
    //...
}

现在,这只是对设备类的一点了解,它实际上集成了更多的东西。这就是它现在再次变得凌乱。

我在实例化“设备”时设置了大约 30 个子类,甚至更多。因此,因为它们是在运行时设置的,所以它们都需要一个必须通过其构造函数的“设备”提供的“工厂”。好吧,我想你明白了。

你是怎么处理的?还是我又走错了路?试图反向依赖所有事物,我是否误解了某些事情?

另一点是,整个故事都将使其可测试,其中 interface 和 autofac 是关键词。但是当使用工厂时,我总是必须使用它自己的类并且不能使用它的接口作为参考,此时不再实现 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 并仅在该类中使用的构造函数中添加依赖项(如 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
{
    //...
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...