0

我正在使用 MVC 3。假设我有一个基本控制器和几个派生控制器。我正在使用 IoC,我的基本控制器构造函数如下所示:

private readonly ICacheProvider _cacheProvider;
private readonly ILoggerProvider _loggerProvider
private readonly IAuditProvider _auditProvider
public abstract class MyControllerBase : Controller
{
  protected MyControllerBase(ICacheProvider cacheProvider, ILoggerProvider loggerProvider, IAuditProvider auditProvider, ...)
  {
    _cacheProvider = cacheProvider;
    _loggerProvider = loggerProvider;
    _auditProvider = auditProvider;
    ...
  }
}

到现在为止还挺好?也许。但是,我的每个派生控制器都需要定义一个与基类构造函数签名匹配的构造函数,例如:

public class MyDerivedController1 : MyControllerBase
{
        public MyDerivedController1(ICacheProvider cacheProvider, ILoggerProvider loggerProvider, IAuditProvider auditProvider, ...)
        : base(cacheProvider, loggerProvider, auditProvider, ...)
    { }
}

这就是我的问题,因为我必须在所有派生控制器中维护“详细”构造函数。如果我需要添加一个新的提供者,我必须重构我所有的派生控制器。

我想我会创建一个 ServiceProvider(或 Service Locator?)类(和 IServiceProvider 接口),它将有一个构造函数和所有提供者作为参数(IoC 将在其中完成它的工作)并将它们作为属性公开。然后我的基本构造函数和派生构造函数将只有 IServiceProvider 作为参数。

但是我担心这种方法会产生一些负面影响,例如: 1- 隐藏实现:除非我检查实现,否则我不知道我使用或需要哪个提供程序。2-难以测试:当构造函数包含参数时,我可以轻松测试它并且我知道会发生什么(自动记录)。

有没有人有任何建议或意见?

4

1 回答 1

0

经过一番研究,我无法找到一个好的解决方案。正如 Daniel Hilgarth 所提到的,控制器有太多的依赖项,这违反了 SRP。我同意。鉴于这是一个现有的应用程序,我无法重构和重新设计整个事情。例如,我想将 ICacheProvider、ILoggerProvider 和 IAudiProvider 等依赖项移动到另一层,该层将负责从存储库中检索数据。

我不想在这里开始新的讨论,但我不喜欢在我的 MVC Web 项目中引用实体框架的想法。我更愿意创建一个数据访问层并完全删除对 EF 的引用。所以,回到我的问题,我有一个带有 X 依赖项的基本控制器,所有派生的控制器都需要一个包含所有这些引用的构造函数(如我上面的问题中所述)。

我考虑了几个选项:

1) 使用服务定位器。在阅读了很多帖子后,我决定忽略此选项。

使用服务定位而不是构造函数注入来避免编写工厂类的负载是否不好

IoC.Resolve 与构造函数注入

http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/

2) 使用聚合服务。这是个好主意,但我无法对依赖项进行分组,因此我决定也忽略这个。

如何避免依赖注入构造函数的疯狂?

http://blog.ploeh.dk/2010/02/02/RefactoringtoAggregateServices/

3) 创建一个新的提供者,它将所有其他依赖项作为属性公开。我对这个选项并不完全满意,因为它以某种方式隐藏了实现细节。但经过所有考虑,我决定实施它。在下面找到创建的新接口和类:

    public interface IMyControllerProvider
    {
    ICacheProvider CacheProvider { get; }

    ILoggerProvider LoggerProvider { get; }

    IAuditProvider AuditProvider { get; }

     ...
    }


    public class MyControllerProvider : IMyControllerProvider
    {
    private readonly ICacheProvider _cacheProvider;
    private readonly ILoggerProvider _loggerProvider;
    private readonly IAuditProvider _auditProvider;
    .....

    public MyControllerProvider(ICacheProvider cacheProvider, ILoggerProvider loggerProvider, IAuditProvider auditProvider, ...)
    {
       _cacheProvider = cacheProvider;
       _loggerProvider = loggerProvider;
       _auditProvider = auditProvider;
       ...
    }

    public ICacheProvider CacheProvider { get { return _context; } }
    public ILoggerProvider LoggerProvider { get { return _context; } }
    public IAuditProvider AuditProvider { get { return _context; } }
}

之后,我重构了我的基本控制器和所有派生控制器以使用 IMyControllerProvider 代替。它工作正常,因为:

1- 派生控制器现在有一个具有单个依赖项的构造函数。

2-虽然新的依赖IMyControllerProvider “隐藏”了真正的依赖,但在测试控制器时,仍然很容易理解还有其他依赖(构造函数记录)。

    private readonly ICacheProvider _cacheProvider;
private readonly ILoggerProvider _loggerProvider
private readonly IAuditProvider _auditProvider
public abstract class MyControllerBase : Controller
{
    protected MyControllerBase(IMyControllerProvider myControllerProvider)
    {
        _cacheProvider = myControllerProvider.CacheProvider;
        _loggerProvider = myControllerProvider.LoggerProvider;
        _auditProvider = myControllerProvider.AuditProvider;
    }
}

public class MyDerivedController1 : MyControllerBase
{
        public MyDerivedController1(IMyControllerProvider myControllerProvider)
          : base(myControllerProvider)
    { }
}

不是最好的解决方案,但考虑到重构整个应用程序的限制,我能想出的唯一解决方案。

于 2013-04-04T16:25:25.617 回答