Ado*_*rez 8 c# architecture unit-testing unity-container mvvm
我正在WPF中构建一个类似Visual Studio的应用程序,我在识别组件的最佳架构设计组织时遇到了一些问题.我计划使用Unity作为我的依赖注入容器和Visual Studio单元测试框架,并且可能使用moq来模拟库.
我将首先描述我的解决方案的结构,然后我的问题:
我有一个WPF项目,其中包含:
另一个名为ViewModel的项目包含:
我的初始化逻辑如下:
var window = Container.Resolve<MainView>();
window.Show();
我的MainView构造函数在其构造函数中接收MainViewModel对象:
public MainView(MainViewModel _mvm)
Run Code Online (Sandbox Code Playgroud)
我的MainViewModel为每个面板都有一个Child ViewModel:
public ToolboxViewModel ToolboxVM{get; set;}
public SolutionExplorerViewModel SolutionExplorerVM { get; set; }
public PropertiesViewModel PropertiesVM { get; set; }
public MessagesViewModel MessagesVM { get; set; }
Run Code Online (Sandbox Code Playgroud)我打算创建一个初始化每个面板的InitializePanels()方法.
现在我的问题是:我的MainViewModel.InitializePanels()如何初始化所有这些面板?给出以下选项:
选项1:手动初始化ViewModels:
ToolboxVM = new ToolboxViewModel();
//Same for the rest of VM...
Run Code Online (Sandbox Code Playgroud)
缺点:
选项2:通过注释我的属性来使用setter注入:
[Dependency]
public ToolboxViewModel ToolboxVM{get; set;}
//... Same for rest of Panel VM's
Run Code Online (Sandbox Code Playgroud)
缺点:
选项3:使用Unity Constructor注入将所有Panel ViewModel传递给MainViewModel构造函数,以便Unity容器自动解析它们:
public MainViewModel(ToolboxViewModel _tbvm, SolutionExploerViewModel _sevm,....)
Run Code Online (Sandbox Code Playgroud)
优点:
缺点:
选项4:在容器堆积中注册我的所有VM类型.然后通过构造函数注入将UnityContainer实例传递给我的MainViewModel:
public MainViewModel(IUnityContainer _container)
Run Code Online (Sandbox Code Playgroud)
这样我可以做类似的事情:
Toolbox = _container.Resolve<ToolboxViewModel>();
SolutionExplorer = _container.Resolve<SolutionExplorerViewModel>();
Properties = _container.Resolve<PropertiesViewModel>();
Messages = _container.Resolve<MessagesViewModel>();
Run Code Online (Sandbox Code Playgroud)
缺点:
鉴于这个冗长的解释,最好的方法是什么,以便我可以利用依赖注入容器并最终获得可单元测试的解决方案?
提前致谢,
首先要做的事情......正如您所注意到的,当单元测试(复杂的VM初始化)时,您当前的设置可能会出现问题.然而,简单地遵循DI原则,依赖于抽象,而不是结果,使这个问题立即消失.如果您的视图模型将实现接口,并且依赖关系将通过接口实现,任何复杂的初始化都变得无关紧要,因为在测试中您只需使用模拟.
接下来,带注释属性的问题是您在视图模型和Unity之间创建了高耦合(这就是为什么它很可能是错误的).理想情况下,注册应该在单个顶级点处理(在你的情况下是bootstrapper),因此容器不以任何方式绑定它提供的对象.您的选项#3和#4是此问题的最常见解决方案,几乎没有注释:
MainViewModel所做的事情,您可能只需要依赖于子视图模型列表,而不是具体的模型.MainViewModel(通过构造函数)手动和注入嘲笑手.我想再说一点.考虑一下项目增长时会发生什么.将所有视图模型打包到单个项目中可能不是一个好主意.每个视图模型都有自己的(通常与其他视图无关)依赖关系,所有这些东西都必须放在一起.这可能很快就难以维持.相反,请考虑是否可以提取一些常见功能(例如消息传递,工具)并将它们放在不同的项目组中(再次分成M-VM-V项目).
此外,当您具有与功能相关的分组时,交换视图会更容易.如果项目结构如下所示:
> MyApp.Users
> MyApp.Users.ViewModels
> MyApp.Users.Views
> ...
Run Code Online (Sandbox Code Playgroud)
为用户编辑窗口尝试不同的视图是重新编译和交换单个程序集(User.Views)的问题.使用一体化方法,您将不得不重建更大部分的应用程序,即使大多数应用程序根本没有改变.
编辑:请记住,更改项目的现有结构(即使是很小的项目)通常是一个非常昂贵的过程,其中包含次要/无业务结果.您可能不被允许或根本无法负担这样做.基于使用的(DAL,BLL,BO等)结构确实有效,随着时间的推移它变得越来越重.您也可以使用混合模式,核心功能按其用法分组,并简单地使用模块化方法添加新功能.
| 归档时间: |
|
| 查看次数: |
4019 次 |
| 最近记录: |