8

在大多数任意应用程序中,有许多横切关注点需要在所有可用层中解决,例如日志记录、消息总线、配置。我注意到,在某些类中,如果使用 IoC 注入模块,它们往往会完全炸毁构造函数。

public class MyService : IService 
{
    public MyService(ILogger logger, IAppSettings settings, IEventBus eventBus...)
    {

    }
}

对于构造函数过度注入的常见情况,我倾向于将关注点重构为紧密相关的构建块,因此我在类中获得更少的依赖关系。然而,这对于横切概念是不可能的。

在日志框架中,静态工厂/服务似乎非常流行,例如

// Application root
MyLoggerService.SetFactory(log4NetFactory);

// Somewhere
MyLoggerService.GetLogger("name") // returns Log4NetLogger created by Log4NetFactory.

我的问题是:对于各种横切的东西,这种方法是一种好方法吗?如果代码最终看起来像这样,有什么缺点:

public class MyService : IService
{

    private readonly IReallyNeedThat _dependency;

    public MyService(IReallyNeedThat dependency)
    {
        _dependency = dependency;
    }

    private readonly ILogger _logger = LoggerService.GetLogger("MyService");
    private readonly IEventBus _eventBus = EventBusService.GetEventBus();
    private readonly IConfiguration _configuration = ConfigurationService.GetConfiguration(Level.Roaming)
    private readonly IExceptionHandler _exceptionHandler = ExceptionPolicy.GetHandler();
    private readonly ITracer _tracer = TraceManager.GetDebugTracer();
}
4

2 回答 2

8

将依赖项移出构造函数并不能解决问题,因为您没有降低类的依赖项数量,并且您仍然违反单一责任原则打开/关闭原则的可能性很大,导致您的代码难以测试、难以改变和难以维护。

相反,一个好的解决方案通常是将这些横切关注点从您的组件中提取出来,并将它们放入专门为该横切关注点定制的组件中,并且该组件包装原始组件。换句话说:创建装饰器

这可能会迫使您更改类的设计,因为当您没有通用抽象来定义相关服务集时,您必须为每个抽象定义一个装饰器,这会导致大量代码重复,即几乎在所有情况下都不好。

因此,相反,围绕命令/处理程序查询/处理程序建模您的系统,您将处于一个更好的位置。您可以使用您定义一次并在所有地方重用的通用装饰器来装饰每个业务逻辑。这使您的系统保持清洁,但仍然非常灵活。

于 2014-08-11T15:34:04.807 回答
6

如果您更关注 TDD,您可以轻松猜出哪种方法更好。

通过依赖注入,您的代码变得更加(单元)可测试。您可以通过一些模拟框架注入依赖项并创建您的单元测试而不会很头疼。

但是在静态工厂的情况下,由于您的工厂类(硬)连接到您的类中,而单元测试没有办法从您的类外部注入它们。

DI 相对于静态工厂的优势 -

  1. 并发开发- 考虑您正在使用的日志服务,它是由其他人构建的,您将对您的代码进行单元测试(并且您不关心日志服务的单元测试,因为您假设它应该是单元使用时经过测试)。您使用 DI,使用模拟对象注入依赖项并完成。

  2. 速度- 在对您的课程进行单元测试时,您绝对不希望它们花费很长时间(这样每次更改主课程时都会让您休息一下;))。您肯定希望您的单元测试在眨眼间运行并报告任何错误。依赖于外部资源(例如网络/数据库、文件系统)的静态工厂将需要时间。您最好使用 DI,使用模拟对象并完成。

  3. 可测试性 - DI 有助于将客户端与其依赖项隔离(促进使用接口),从而提高可测试性(通过使用模拟)。

于 2014-08-11T11:33:24.420 回答