在使用PRISM和Enterprise Library处理大量CRUD操作的LOB桌面应用程序时,我注意到一个看似烦人的重复模式。对于每个域模型实体(例如Contact),我发现我用视图模型(例如ContactVM)自我包装然后我引入一个新的ContactsVM
(注意's'),后一个类接受一个存储库接口用于填充ObservableCollection<ContactVM>
以及我从存储库中读取的每个Contact
实体,我将其包装在ContactVM
中,我将实体传递给构造函数以及其他企业我的ViewModel需要的图书馆服务。
问题是我的所有视图模型构造函数都开始采用这样的模式:
ViewModel(EntityToWrap e, DependencyFromEntLib, OtherDependencies ...)
现在这是一个问题,因为大多数工具和库需要默认的无参数构造函数(例如,某些商业数据网格需要提供过滤支持),而且您不能使用设计数据来实现实体可视化,因为它们也需要无参数构造函数。最后一个问题:构建视图模型的正确方法是什么?应该通过构造函数还是通过ServiceLocator提供Entlib服务?
答案 0 :(得分:11)
以下是解决问题的众多不同方法之一。
我更喜欢更轻量级的视图模型。然后我添加一个类,其职责是从一个或多个源(例如存储库)组成视图模型。这并没有消除级联依赖的问题,但它确实释放了视图模型构造函数。
它还保留了控制器之外的逻辑,并允许重复使用视图模型(当然,适当时)。
轻量级视图模型
轻量级控制器知道如何定位组装视图模型的编写器(您可以使用DI框架来设置具有所有依赖关系的编辑器)。控制器可能在设置过程中起到次要作用,但应保持简单。
Controller知道如何组装视图模型,并与composer类共享。例如,该操作可能会请求一个摘要视图,该摘要视图仍然可以利用相同的视图模型而不会填充子项。
Composer汇总了完成视图模型所需的信息。作曲家可以使用其他作曲家来收集不直接负责的信息。同样,这里可以使用DI框架,这样这些作曲家也可以获得他们需要的依赖。
Controller使用完整的视图模型照常渲染视图。
在我看来,这也提供了更好的抽象层次。仅仅因为视图模型通常看起来像特定的域模型,这并不意味着它总是如此。
最终结果:
很多课程(缺点,授予),但代码重复最少(即DRY)
可测试的薄视图模型(如果需要......它们可能无需测试)
薄而可测试的控制器。
可测试的作曲家对象可以重复用于不同的场景,因为他们(可能)知道如何为各种目的组装视图模型。
灵活地混合和匹配视图模型,控制器和作曲家,以支持不同的场景。