在基类中具有ALL依赖项是一种好习惯吗?

时间:2018-08-23 11:43:46

标签: c# wpf mvvm dependency-injection

我有一个使用MVVM模式的WPF应用程序。我正在使用Autofac作为DI容器。像其他类似于我的应用程序一样,我有一个ViewModelBase类,该类实现INotifyPropertyChanged接口,并且还解析在容器中注册的依赖项:

public class ViewModelBase : ObservableObject
{
    protected IErrorHandler _errorHandler;
    protected IEventAggregator _eventAggregator;
    protected ICustomDialogService _customDialogService;
    protected IUserSettingsRepository _userSettingsRepository;
    protected IReferralRepository _referralRepository;
    protected Notification _notification;
    protected IPrinting _printingService;
    protected ILookupRepository _lookupRepository;
    protected IWorklistRepository _worklistRepository;
    protected IDialogCoordinator _dialogCoordinator;

    public ViewModelBase()
    {
        _errorHandler = AppContainer.Resolve<IErrorHandler>();
        _eventAggregator = AppContainer.Resolve<IEventAggregator>();
        _customDialogService = AppContainer.Resolve<ICustomDialogService>();
        _userSettingsRepository = AppContainer.Resolve<IUserSettingsRepository>();
        _referralRepository = AppContainer.Resolve<IReferralRepository>();
        _notification = AppContainer.Resolve<Notification>();
        _printingService = AppContainer.Resolve<IPrinting>();
        _lookupRepository = AppContainer.Resolve<ILookupRepository>();
        _worklistRepository = AppContainer.Resolve<IWorklistRepository>();
        _dialogCoordinator = AppContainer.Resolve<IDialogCoordinator>();
    }
}

该应用程序有大约20个视图模型,所有视图模型都需要使用不同的依赖项-有时将不需要。每个视图模型都可以访问这些依赖关系(即使永远不会使用它们)是一种好习惯吗?

2 个答案:

答案 0 :(得分:4)

通常,您是通过类构造函数或类似的方法提供依赖项的,而不是从构造函数内部提供的。因此,实际上您的课程都不应该知道您的DI容器的所有内容。相反,容器在 calling 上下文中解析依赖项,并将其提供给类构造函数。解决呼叫依存关系的呼叫者责任,不是班级的责任。这是控制原理反转的重点。

话虽如此,您的依存关系应通过以下方式解决:

var errorHandler = AppContainer.Resolve<IErrorHandler>();
var eventAggregator = AppContainer.Resolve<IEventAggregator>();
var myModel = new MyModel(errorHandler, eventAggregator);

通过这种方式myModel仅获得正常运行所需的依赖项。

要创建另一个模型:

var customDialogService = AppContainer.Resolve<ICustomDialogService>();
var userSettingsRepository = AppContainer.Resolve<IUserSettingsRepository>();
var myModel = new MyModel2(customDialogService, userSettingsRepository);

答案 1 :(得分:3)

您的ViewModelBase类出现以下问题:

  • 它使用Service Locator anti-pattern。这使得类的依赖关系变得不明显。
  • 暴露于其衍生产品,而不是将其与衍生产品的行为隐藏起来,从而导致衍生产品违反Single Responsibility Principle
  • li>
  • 基类始终与它们的派生类强烈耦合,如果具有,则其行为也是如此。这会使测试复杂化,并且通常会使衍生产品复杂化。

因此,使用包含依赖项或 volatile 行为(即您希望在测试套件中模拟,替换或拦截的行为)的基类是个坏主意。

其他方法比使用基类对公共依赖项进行分组更为有效,例如:

  • 使用装饰器或拦截器来应用横切关注点
  • 使用Facade Services隐藏依赖项组及其行为
  • 将派生分解成较小的类,以便它们需要更少的依赖项。
  • 使用构造函数注入而不是Service Locator反模式。