我很久以来一直在想这个社区里住着什么我说的是面向业务的大型WPF/Silverlight企业应用程序。
从理论上讲,有不同的模式在发挥作用:
- 数据模型(通常链接到数据库表、Edmx/NHibernate/..Map实体)
- 业务模型(包含实际业务逻辑的类)
- 传输模型(向外界/客户端公开的类(dto))
- 视图模型(实际视图绑定到的类)
很明显,这种分离有其明显的优点;但它在现实生活中能正常工作吗?是一场维护噩梦吗?
那么你该怎么做呢?在实践中,你对所有这些模型使用不同的类模型吗?我已经看到了很多关于这个的变体,例如:
- 数据模型=业务模型:数据模型首先实现代码(作为POCO),并用作业务模型,同时包含业务逻辑
- 业务模型=调拨模型=查看模型:业务模型被如此展示给客户端;未Map到DTO的..。视图直接绑定到此业务模型
- Silverlight RIA服务,开箱即用,具有公开的数据模型:数据模型=业务模型=传输模型,有时甚至传输模型=视图模型。
- ..
我知道,"视情况而定"的答案已经到位;但这取决于什么呢?你用过哪些方法,你是如何回顾的?
感谢分享,
问候你Koen
4条答案
按热度按时间bwntbbo31#
问得好。我从来没有编写过真正企业级的代码,所以我的经验有限,但我会开始的。
我当前的(WPF/WCF)项目使用数据模型=业务模型=传输模型=视图模型!没有DB后端,所以“数据模型”实际上是序列化为XML的业务对象。
我尝试过DTO,但很快发现内务处理极其困难,而且我内心永远存在的过早优化者不喜欢不必要的复制。这可能会反过来咬我一口(例如,通信序列化有时与持久性序列化有不同的需求),但到目前为止还不是一个大问题。
我的业务对象和视图对象都需要值更改的推送通知,因此使用相同的方法(INotifyPropertyChanged)实现它们是有意义的。这有一个很好的副作用,即我的业务对象可以直接绑定到WPF视图中,尽管使用MVVM意味着ViewModel可以在需要时轻松提供 Package 器。
到目前为止,我还没有遇到任何主要的障碍,而且只维护一组对象可以使事情变得简单,我不敢想象如果我把所有四个“模型”都分开,这个项目会有多大。
我当然可以看到拥有单独对象的好处,但对我来说,直到它实际成为一个问题之前,它似乎是浪费精力和复杂性。
正如我所说的,这都是相当小的规模,旨在运行在几十台PC上。我很有兴趣阅读其他来自真正的企业开发人员的回应。
b1zrtrql2#
这种分离一点也不可怕,事实上,自从使用MVVM作为设计模式以来,我非常支持它的使用。我最近是一个团队的一员,我使用MVVM编写了一个相当大的产品的UI组件,它与一个服务器应用程序交互,处理所有的数据库调用等,可以诚实地说,这是我工作过的最好的项目之一。
这个项目
我已经将传输模型归类为一个东西,但实际上它是作为几层构建的。
我还有一系列ViewModel类,它们是Model类的 Package 器,用于添加额外的功能或更改数据的显示方式,这些类都支持INPC,并且是我的UI绑定到的类。
我发现MVVM方法非常有用,老实说,它使代码保持简单,每个视图都有一个对应的视图模型,用于处理该视图的业务逻辑,然后有各种底层类被视为模型。
我认为通过像这样分离代码可以使事情更容易理解,每个视图模型都没有混乱的风险,因为它只包含与其视图相关的内容,视图模型之间的任何公共内容都通过继承来处理,以减少重复代码。
当然,这样做的好处是代码立即变得更易于维护,因为在我的应用程序中,对数据库的调用是通过对服务的调用来处理的,这意味着服务方法的工作方式可以更改,只要返回的数据和所需的参数保持不变,UI就永远不需要知道这一点。UI没有代码隐藏意味着UI可以很容易地调整。
缺点是,可悲的是,有些事情你只是不得不做代码背后的原因,除非你真的想坚持MVVM和一些过于复杂的解决方案,所以在某些情况下,它可能很难或不可能坚持一个真正的MVVM实现(在我们公司,我们认为这是没有代码背后).
总之,我认为如果你正确地利用继承,坚持设计模式,并执行编码标准,这种方法工作得很好,如果你开始偏离,但事情开始变得混乱。
2exbekwf3#
几个层次不会导致维护的噩梦,而且你拥有的层次越少-维护它们就越容易。我会试着解释为什么。
**1)**传输模型不应与数据模型相同
例如,ADO .NET实体数据模型中有以下实体:
并且您希望从WCF服务返回它,因此您编写如下代码:
还有一个问题:服务的使用者如何确保
Region
和Orders
属性不为null或空?如果Order
实体有OrderDetail
实体的集合,它们也会被序列化吗?有时候你可能忘记关闭延迟加载,整个对象图将被序列化。以及其他一些情况:
File
表中除二进制数组类型的列FileContent
之外的所有信息。所以我想你已经确信自动生成的实体不适合Web服务,这就是为什么我们应该创建一个这样的传输模型:
而且您可以自由地更改数据库中的表而不影响Web服务的现有使用者,也可以更改服务模型而不更改数据库。
为了简化模型转换过程,可以使用AutoMapper库。
**2)**建议视图模型不应与传输模型相同
尽管您可以将传输模型对象直接绑定到视图,但它将只是一个“OneTime”关系:模型的变化不会反映在视图中,反之亦然。视图模型类在大多数情况下会向模型类添加以下特性:
INotifyPropertyChanged
接口通知属性更改ObservableCollection
类通知集合更改{Binding Converter...}
,但在视图模型的一侧同样,有时候您需要将多个模型组合在一个视图中显示它们,最好不要依赖于服务对象,而是定义自己的属性,这样,如果模型的结构发生变化,视图模型将保持不变。
我总是使用上面描述的3层来构建应用程序,它工作得很好,所以我建议每个人都使用同样的方法。
nlejzf6q4#
我们使用了一种类似于Purplegoldfish发布的方法,但增加了一些层。我们的应用程序主要与Web服务通信,因此我们的数据对象不绑定到任何特定的数据库。这意味着数据库模式的更改不一定会影响UI。
用户界面层由以下子层组成:
1.数据模型:这包括支持更改通知的普通数据对象。这些是专门在UI上使用的数据模型,因此我们可以灵活地设计这些对象以满足UI的需要。当然,其中一些对象并不普通,因为它们包含操作其状态的逻辑。此外,因为我们使用了大量数据网格,每个数据模型负责提供其可以绑定到网格的属性列表。
1.视图:我们对视图的XAML定义。为了适应一些复杂的需求,我们不得不在某些情况下求助于代码隐藏,因为坚持只使用XAML的方法太乏味了。
1.视图模型:这是我们为视图定义业务逻辑的地方,这些人还可以访问由数据访问层中的实体实现的接口,如下所述。
1.模块演示者:这通常是一个负责初始化模块的类。它的任务还包括注册与此模块关联的视图和其他实体。
然后,我们有一个数据访问层,其中包含以下内容:
1.传输对象:这些通常是由Web服务公开的数据实体,其中大部分是自动生成的。
1.数据适配器,如WCF客户端代理和任何其他远程数据源的代理:这些代理通常实现一个或多个暴露给ViewModel的接口,并负责异步地对远程数据源进行所有调用,根据需要将所有响应转换为UI等效数据模型。2在某些情况下,我们使用AutoMapper进行转换,但所有这些都是专门在这一层完成的。3我们的分层方法有点复杂,应用程序也是如此。它必须处理不同类型的数据源,包括网络服务、直接数据库访问和其他类型的数据源,如OGC网络服务。