我一直想知道现在社区里生活的人已经有一段时间了; 我说的是面向业务的大型WPF / Silverlight企业应用程序。
理论上,有不同的模型在起作用:
很明显,这种分离具有明显的优势; 但它在现实生活中有效吗?这是一场维护噩梦吗?
那你做什么? 在实践中,您是否为所有这些模型使用不同的类模型? 我已经看到了很多变化,例如:
我知道“这取决于”答案在这里已经存在; 但那取决于它取决于什么; 您使用了哪种方法,以及如何回顾它?
感谢分享,
此致 柯恩
答案 0 :(得分:2)
好问题。我从来没有编写任何真正的企业,所以我的经验有限,但我会开始。
我当前的(WPF / WCF)项目使用Data Model = Business Model = Transfer Model = View Model! 没有数据库后端,因此“数据模型”实际上是将业务对象序列化为XML。
我和DTO一起玩过,但很快发现家务管理工作极其艰难,而且我现在的过早优化者不喜欢所涉及的不必要的复制。这可能会让我感到困惑(例如,通信序列化有时会有不同于持久化序列化的需求),但到目前为止它并没有太大的问题。
我的业务对象和视图对象都需要推送值更改通知,因此使用相同的方法(INotifyPropertyChanged)实现它们是有意义的。这有很好的副作用,我的业务对象可以直接绑定到WPF视图中,尽管使用MVVM意味着ViewModel可以在需要时轻松提供包装。
到目前为止,我还没有遇到任何重大障碍,并且维护一组对象可以保持简单。如果我将所有四个“模型”拆分出来,我会想到这个项目会有多大。
我当然可以看到拥有单独对象的好处,但对我来说,直到它实际上成为一个问题,它似乎浪费了精力和复杂性。
正如我所说,这个规模相当小,旨在运行在几十台PC上。我有兴趣阅读真正的企业开发人员的其他回复。
答案 1 :(得分:0)
分离根本不是一场噩梦,因为使用MVVM作为设计模式我非常支持它的使用。我最近是一个团队的一员,我使用MVVM编写了一个相当大的产品的UI组件,它与处理所有数据库调用等的服务器应用程序交互,并且老实说它是我工作过的最好的项目之一。 / p>
这个项目有一个
我将Transfer模型归为一类,但实际上它是构建为多层的。
我还有一系列ViewModel类,这些类是Model类的包装器,可以添加其他功能或更改数据的呈现方式。这些都支持INPC,是我的UI绑定的。
我发现MVVM方法非常有用,并且说实话它保持代码简单,每个视图都有一个相应的视图模型来处理该视图的业务逻辑,然后有各种基础类被认为是模型。
我认为通过分离这样的代码可以让事情更容易理解,每个View Model都没有混乱的风险,因为它只包含与其视图相关的东西,我们在视图模型之间通用的任何东西都被处理掉了通过继承来减少重复的代码。
这样做的好处当然是代码变得更加可维护,因为调用数据库是在我的应用程序中通过调用服务来处理的,这意味着可以更改服务方法的工作方式,当返回的数据和所需的参数保持不变时,UI永远不需要知道这一点。 UI也是如此,没有代码隐藏的UI意味着UI可以很容易地调整。
缺点是,遗憾的是,你无需出于某种原因需要在代码中执行某些操作,除非你真的想坚持MVVM并想出一些过于复杂的解决方案,所以在某些情况下很难或不可能坚持真实MVVM实现(在我们公司,我们认为这不是代码背后)。
总之,我认为如果你正确地使用继承,坚持设计模式并强制执行编码标准这种方法非常有效,如果你开始偏离,但事情开始变得混乱。
答案 2 :(得分:0)
多层不会导致维护噩梦,而且你拥有的层数越少 - 维护它们就越容易。我会试着解释原因。
1)传输模型不应与数据模型
相同例如,您的ADO.Net实体数据模型中包含以下实体:
Customer
{
int Id
Region Region
EntitySet<Order> Orders
}
并且您希望从WCF服务返回它,因此您可以编写如下代码:
dc.Customers.Include("Region").Include("Orders").FirstOrDefault();
还有一个问题:服务的消费者如何确保Region
和Orders
属性不为空或空?如果Order
实体有OrderDetail
个实体的集合,它们也会序列化吗?有时您可能忘记关闭延迟加载,整个对象图将被序列化。
以及其他一些情况:
您需要组合两个实体并将它们作为单个对象返回。
您只想返回实体的一部分,例如File
表中除二进制数组类型的列FileContent
之外的所有信息。
您想要从表中添加或删除某些列,但不希望将新数据公开给现有应用程序。
所以我认为您确信自动生成的实体不适合Web服务。 这就是我们应该创建这样的转移模型的原因:
class CustomerModel
{
public int Id { get; set; }
public string Country { get; set; }
public List<OrderModel> Orders { get; set; }
}
您可以自由更改数据库中的表,而不会影响Web服务的现有使用者,也可以在不更改数据库的情况下更改服务模型。
为了简化模型转换过程,您可以使用AutoMapper库。
2)建议视图模型不要与传输模型相同
虽然您可以将传输模型对象直接绑定到视图,但它只是“OneTime”关系:模型的更改不会反映在视图中,反之亦然。 在大多数情况下,视图模型类将以下功能添加到模型类中:
使用INotifyPropertyChanged
界面
使用ObservableCollection
类
确认属性
对视图事件的反应(使用命令或数据绑定和属性设置器的组合)
转换属性,类似于{Binding Converter...}
,但在视图模型一侧
有时,您需要组合多个模型以在单个视图中显示它们。最好不依赖于服务对象,而是定义自己的属性,这样如果模型的结构发生变化,视图模型将是相同的。
我总是使用上面描述的3层来构建应用程序并且工作正常,所以我建议大家使用相同的方法。
答案 3 :(得分:0)
我们使用的方法类似于Purplegoldfish发布的一些额外图层。我们的应用程序主要与Web服务通信,因此我们的数据对象不绑定到任何特定的数据库。这意味着数据库架构更改不一定会影响UI。
我们有一个用户界面层,包含以下子层:
数据模型:这包括支持更改通知的纯数据对象。这些是专门用于UI的数据模型,因此我们可以灵活地设计这些模型以满足UI的需求。或者当然,其中一些对象并不简单,因为它们包含操纵其状态的逻辑。此外,由于我们使用了大量数据网格,因此每个数据模型都负责提供可绑定到网格的属性列表。
观点:我们对视图的XAML定义。为了满足一些复杂的要求,我们不得不在某些情况下使用代码,因为坚持使用XAML的方法太繁琐了。
ViewModels:这是我们为视图定义业务逻辑的地方。这些人还可以访问由我们在下面描述的数据访问层中的实体实现的接口。
模块演示者:这通常是一个负责初始化模块的类。其任务还包括注册与该模块相关的视图和其他实体。
然后我们有一个数据访问层,其中包含以下内容:
传输对象:这些通常是由Web服务公开的数据实体。其中大部分是自动生成的。
数据适配器,例如WCF客户端代理和任何其他远程数据源的代理:这些代理通常实现一个或多个暴露给ViewModel的接口,并负责异步调用远程数据源,转换所有根据需要响应UI等效数据模型。在某些情况下,我们使用AutoMapper进行翻译,但所有这些都是在此层中完成的。 我们的分层方法有点复杂,应用也是如此。它必须处理不同类型的数据源,包括Web服务,直接数据库访问和其他类型的数据源,如OGC Web服务。