服务定位器反模式及其替代方案

在软件开发中,服务定位器(Service Locator)是一种常见的设计反模式,它指的是在代码库中任意位置调用IoC容器来解析对象的依赖关系。这种模式破坏了封装性,因为依赖关系在调用者和被调用者之间是不可见的,这可能导致运行时异常,尤其是当调用者没有正确配置IoC容器以满足所需的依赖关系时。

为了解决这个问题,建议将依赖关系的解析移动到对象的构造函数中。这样,调用者就能清楚地知道对象需要哪些依赖关系。以下是一个示例代码,展示了如何通过构造函数注入来避免服务定位器反模式:

public class OrderProcessor : IOrderProcessor { private readonly IOrderValidator validator; private readonly IOrderShipper shipper; public OrderProcessor(IOrderValidator validator, IOrderShipper shipper) { this.validator = validator; this.shipper = shipper; } public void Process(Order order) { if (validator.Validate(order)) { shipper.Ship(order); } } }

然而,在某些情况下,如WPF应用程序中的ViewModel,可能需要多个依赖关系,这会导致构造函数声明过于复杂。例如,一个ViewModel可能需要IEventAggregator、IProgress和IPromptCreator等依赖关系。在这种情况下,构造函数可能会变得非常混乱。

为了解决这个问题,可以使用MEF(Managed Extensibility Framework)进行依赖注入。通过将依赖关系从构造函数移动到字段声明,并使用Import属性进行标记,可以简化构造函数。这样,虽然没有直接调用IoC容器,但仍然隐藏了依赖关系。以下是使用MEF进行依赖注入的示例代码:

[Export] public class PaymentViewModel : ICanPay { [Import] protected IEventAggregator aggregator; [Import] protected IProgress progress; [Import] protected IPromptCreator promptCreator; public PaymentViewModel(IPaymentSystem paymentSystem, IRulesValidator rulesValidator) { } public void PayFor(Order order) { // 使用aggregator, progress, promptCreator } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485