c# - IoC 工厂 : Pros and contras for Interface versus Delegates

标签 c# .net design-patterns dependency-injection ioc-container

任何需要运行时值来构造特定依赖项的地方,抽象工厂都是解决方案。

我的问题是:为什么许多消息来源更喜欢 FactoryInterface 而不是 FactoryDe​​legate 来实现这种模式? 这两种解决方案的优缺点是什么?

下面是一个例子来理解我的意思

如果您有一个服务需要一个具有特定上下文的存储库,那么服务构造函数 需要一个工厂来创建或访问其存储库。

常见的解决方案是像这样创建一个RepositoryFactoryInterface

public IRepositoryFactory {
    IRepository Create(ContextInformation context);
}

public class MyService {
    private IRepositoryFactory repositoryFactory;
    public MyService(IRepositoryFactory repositoryFactory)
    {
        this.repositoryFactory = repositoryFactory:
    }

    public void DoSomeService()
    {
        ContextInformation context = ....;

        IRepository repository = this.repositoryFactory.Create(context);

        repository.Load(...);
        ...
        repository.Save(...);
    }
}

您还需要以某种方式实现 IRepositoryFactory 接口(interface)

public MyEf4RepositoryFactory : IRepositoryFactory
{
    IRepository Create(ContextInformation context)
    {
        return new MyEf4Repository(context);
    }
}

...并在应用程序中使用它

public void main()
{
    IRepositoryFactory repoFactory = new MyEf4RepositoryFactory();
    IService service = new MyService(repoFactory); 

    service.DoSomeService();
}

----- 主流方案结束------

除了 RepositoryFactoryInterface,您还可以使用 factorydelegate 执行相同的操作,这样需要更少的编码。

public class MyService {
    private Func<ContextInformation, IRepository> repositoryFactory;
    public MyService(Func<ContextInformation, IRepository> repositoryFactory)
    {
        this.repositoryFactory = repositoryFactory:
    }

    public void DoSomeService()
    {
        ContextInformation context = ....;

        IRepository repository = this.repositoryFactory(context);

        repository.Load(...);
        ...
        repository.Save(...);
    }
}

...并在应用程序中使用它

public void main()
{
    IService service = new MyService(context => new MyEf4Repository(context)); 

    service.DoSomeService();
}

在我看来,factorydelegate context => new MyEf4Repository(context) 比 声明和实现接口(interface) IRepositoryFactoryMyEf4RepositoryFactory

这一定是有原因的,我想知道为什么。

这是一个使用接口(interface)方法的示例源:answer to is-there-a-pattern-for-initializing-objects-created-via-a-di-container

[更新]在问了这个问题 15 个月后,有了更多 java universers 的经验,我改变了主意:现在我更喜欢接口(interface)而不是委托(delegate)。但我不能说为什么。这只是一种感觉。也许是因为我更习惯了?

最佳答案

Any place where you need a run-time value to construct a particular dependency, Abstract Factory is the solution.

我会反对这一点。不应使用运行时数据构建依赖关系,如 explained here .总之,文章指出:

Don't inject runtime data into application components during construction; it causes ambiguity, complicates the composition root with an extra responsibility and makes it extraordinarily hard to verify the correctness of your DI configuration. Instead, let runtime data flow through the method calls of constructed object graphs.

当我们改为让运行时数据“流经构造对象图的方法调用”时,您会发现抽象工厂的用处在下降。当使用运行时数据从多个依赖项中进行选择时(与将运行时数据注入(inject)依赖项相比),它们可能仍会被使用,但即便如此,抽象工厂通常也不是最佳解决方案,因为 explained here .总之,文章指出:

Generally, the use of a factory abstraction is not a design that considers its consumers. According to the Dependency Injection Principle (DIP), abstractions should be defined by their clients, and since a factory increases the number of dependencies a client is forced to depend upon, the abstraction is clearly not created in favor of the client and we can therefore consider this to be in violation of the DIP.

相反,Facade、Composite、Mediator 和 Proxy 等模式通常是更好的解决方案。

这并不意味着您的应用程序中不能包含产生依赖关系的代码,但不应将其定义为由其他应用程序组件使用的抽象。相反,应该将类似工厂的行为封装到定义为 Composition Root 的一部分的适配器中。 .

当您只有这些类似工厂的逻辑和依赖项作为组合根的一部分时,是否定义 IRepositoryFactory 并不重要或者仅仅使用 Func<IRepository>构建这样的依赖关系,因为 IRepositoryFactory也会在组合根中定义(因为应用程序没有使用此类工厂的业务)。

也就是说,在极少数情况下抽象工厂是正确的抽象(这通常会在构建可重用框架时发生),我确实发现工厂接口(interface)的使用比委托(delegate)的使用更能揭示意图。它有点冗长,但更清楚这样的事情的含义。一个IControllerFactoryFunc<IController> 更能说明问题.

我会说这更适用于不产生依赖性而是产生数据值的工厂。以注入(inject) Func<DateTime> 为例进入构造函数。这实际上意味着什么,它返回什么值?它返回 DateTime.Now 是否直观? , 还是返回 DateTime.Today , 或者是其他东西?在那种情况下,定义一个 ITimeProvider 会更清楚。与 GetCurrentTime() 的接口(interface)方法。

注意:此答案于 2017 年 7 月更新以反射(reflect)我的最新观点。

关于c# - IoC 工厂 : Pros and contras for Interface versus Delegates,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5404084/

相关文章:

c# - “Data.Repository.UnitofWork”未实现接口(interface)成员 'Data.Repository.IUnitofWork.Customer'

c# - 如何阅读 MVC OWIN AuthenticationProperties?

c# - 从绑定(bind)到 DataGridView 的 DataTable 中删除最后一个 DataRow 时如何防止出错?

java - 设计模式-单个对象只能存在于单个事件中

Java通过多线程共享对象 - 需要设计模式

C# await Task.Delay(1000);仅需 640ms 返回

c# - 在 C# 中这种委托(delegate)用法的名称是什么?

.net - .NET 中队列 <T> 的大小限制?

java - 实现需要访问 secret 数据的 Java 桌面应用程序

c# - 如何将 XmlNodeList 转换为 NodeSet 以在 XSLT 中使用?