在我正在进行的项目中,我添加了一个基本ViewModel类,其中包含所有ViewModel共有的一些功能和依赖项。它通过以下属性提供验证,消息传递,调度和导航服务:
IValidateProperties Validator { get; }
IMessenger Messenger { get; }
IDispatcherHelper DispatcherHelper { get; }
INavigationService Navigation { get; }
我使用IoC容器来连接我的依赖项,但是我有一些选项来处理这些依赖项,这些依赖项对于我的所有ViewModel都是通用的:
在构造函数中注入它们。如果我这样做,那么它需要将这四个参数添加到每个ViewModel的构造函数中,并将它们传递给基础构造函数。我的代码库中添加了很多额外的噪音,我真的很想避免。另外,如果我要在某个时刻添加另一个依赖项,则需要更改每个ViewModel的构造函数。
使用属性注入。这是我现在正在使用的方法。不幸的是,这意味着在构建ViewModel之后才能访问这些属性,从而导致以下解决方法:
private IValidateProperties _validator;
public IValidateProperties Validator
{
get => _validator;
set
{
_validator = value;
_validator.ValidationTarget = this;
}
}
private IMessenger _messenger;
public IMessenger Messenger
{
get => _messenger;
set
{
_messenger = value;
MessengerAttached();
}
}
protected virtual void MessengerAttached() { }
将属性设为静态,并在应用启动时将其注入。对于Messenger
,DispatcherHelper
和Navigation
来说这很容易,因为无论如何它们都被用作单身人士。对于Validator
,我需要添加静态ValidatorFactory
,并使用工厂在构造函数中实例化Validator
。这种方式似乎是最干净的做事方式,但我有这个声音在我脑后告诉我,使用这样的静态是一个坏主意。
我觉得选项1是不可能的,因为它会导致添加到我的ViewModel中的大量嘈杂的样板代码。我仍然不确定2或3是否是最佳方式。在这种情况下,使用静力学是一个坏主意还是一个很好的理由,或者我是否在烦恼?
有些人认为静态导致不可测试的代码,但在这种情况下,它实际上会使事情更容易测试。如果我使用选项3,我可以为我的所有视图模型测试添加以下类来继承:
public abstract class ViewModelTestBase
{
protected readonly IValidateProperties ValidatorMock;
protected readonly IMessenger MessengerMock;
protected readonly IDispatcherHelper DispatcherHelperMock;
protected readonly INavigationService NavigationMock;
protected ViewModelTestBase()
{
ValidatorMock = Substitute.For<IValidateProperties>();
ViewModelBase.Validator = ValidatorMock;
MessengerMock = Substitute.For<IMessenger>();
ViewModelBase.Messenger = MessengerMock;
DispatcherHelperMock = Substitute.For<IDispatcherHelper>();
ViewModelBase.DispatcherHelper = DispatcherHelperMock;
NavigationMock = Substitute.For<INavigationService>();
ViewModelBase.Navigation = NavigationMock;
}
}
那么,有什么具体的理由不采用方法#3?如果在这种情况下静态确实是一个坏主意,那么有什么具体的理由不采用方法#2呢?