在软件开发中,服务定位器(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
}
}