客户端MV * - 模型应该有保存方法吗?

时间:2014-05-16 16:50:05

标签: javascript angularjs model-view-controller knockout.js ember.js

所以这是一个通用的模式问题,但我已经和我一起来回走了一段时间。

模型是否应该在MV *中使用保存方法?

我经常在Knockout,Ember和有时甚至是Angular之间来回跳转,但我常常遇到的一个问题就是模型在它的类或原型上有一个保存方法,它知道如何保存更改以减少依赖性服务上的应用程序(也就是模型有一个服务,用于保存所有其他视图模型/控制器通过了解模型继承)或者是否应该有一个服务,每个视图模型/控制器依赖于具有特定方法的服务用于保存对象的更改?

示例JavaScript伪代码

var person = new Model.Person();
person.name = 'Bill';
person.save();

VS

var personService = require('services/person.service');
var person = new Model.Person();
person.name = 'Bill';
personService.save(person);

两者都实现了保存此人的相同目的,但在示例1中,视图模型/控制器不知道服务或如何实现它,只有当您想要更改某个人时,才能保存它。在示例二中,我们不仅要了解保存方法,还要了解如何实现保存。

请在回答之前阅读 -

我意识到这是一个基于意见的问题,但是如果你能用事实来支持你的意见,那将是事实,所以请提及备份任何声明,以便不会因为'主要基于意见'而关闭< / p>

2 个答案:

答案 0 :(得分:12)

这取决于模式(而不是所有基于imo的观点)。

  • 您的第一个示例:具有.save方法的域对象称为ActiveRecord(另请参阅here)。

  • 您的第二个示例:数据映射和域图层之间的映射器称为Repository(另请参阅here

活动记录模式

引用福勒:

  

在数据库表或视图中包装行的对象,封装数据库访问,并在该数据上添加域逻辑。

ActiveRecord模式通常擅长原型设计,有时在非常小的应用程序中是一个好主意,在这些应用程序中,对象和数据库行之间存在1-1映射。通常,您希望将持久化对象的逻辑与实际域对象的逻辑分开,因为它们本质上是不同的职责。

这是逻辑上处理数据持久性的最简单方法之一。

enter image description here

例如,这是Backbone模型和集合使用sync()方法执行的操作。这导致它们持久存储到服务器。通常,您会看到较大的Backbone应用程序完全不使用sync()来支持实现自己的适配器。毕竟,在Backbone世界中,它强制在您的REST API和您的域对象之间建立1-1映射,从而有效地使您的域对象和数据传输对象相同,随着应用程序的增长,这些对象会变得难以维护。

存储库模式

再次引用福勒:

  

使用类似集合的接口访问域对象,在域和数据映射层之间进行调解。

对于较大的应用程序,存储库通常是更好的设计模式,因为它从域对象中删除了持久性逻辑,因此它做得更好separation of concerns

实施明智,存储库通常如下所示: Repository

但是,对于其用户,存储库可能如下所示:

enter image description here

作为任何抽象,责任的另一个对象有一些开销,但是随着应用程序的增长,它开始得到回报。如果您使用Angular创建$resource并将其包装在将这些对象从db查询映射到域对象(您的数据映射器)的服务中,然后像集合一样查询该服务 - 那是一个存储库你。

答案 1 :(得分:1)

我个人认为简短的回答是你的第二个版本。我通常认为客户端上的viewmodel基本上是一包数据或属性。服务用于持久化/从服务器获取这些视图模型,控制器负责使用服务方法并呈现视图。在Angular.js中,world指令会处理任何特定于DOM的行为,但我认为最终由于UI交互(保存,验证等)而发生的事件将由控制器处理(可能通过调用服务)方法)。

当我开始使用Angular.js并且正在通过他们的开发人员documentation时,我提出了这个意见。缺点是:

使用控制器:

  • 设置viewmodel对象的初始状态
  • 向viewmodel对象添加行为

请勿使用控制器:

  • 操纵DOM - 控制器应仅包含业务逻辑。
  • 格式输入
  • 过滤输出
  • 管理其他组件的生命周期(例如,创建 服务实例)。

使用服务在整个应用中整理和分享代码和状态。