2

是的,另一个关于 Web 应用程序的 MVC 架构中职责分离的问题 - 我认为这个有一个微妙的区别......

我现有的实现如下所示:

  • 控制器:非常“薄”;A除了调用模型和视图,仅路由和表示逻辑
  • 型号:非常“厚”;所有业务逻辑
  • 视图:非常“薄”;除了内容和标记,代码仅限于循环和数据格式

此外,该项目使用 ORM 作为数据库之上的抽象层,并使用“连接器”作为外部服务的包装类。

我的问题涉及模型之间的职责分离。在大多数情况下,我们的模型模仿了我们系统中的“事物”——“用户”、“产品”、“订单”等。

我发现这对于服务简单的数据检索请求非常有效——控制器实例化正确的模型并调用相关的“getter”。

当启动更复杂的流程(例如“PlaceOrder”或“RegisterUser”)时,就会出现问题。有时这些过程可以在单个模型中实现,有时它们需要模型之间的通信或协调才能实现。

就目前而言,在这些情况下,模型直接相互通信,而不是由控制器管理的过程。将流程保留在模型中似乎是正确的(例如,控制器不需要知道“注册用户”的业务规则需要发送确认电子邮件)。

我在这个实现中发现了两个让我有些担心的问题:

  1. 模型通常似乎对其他模型了解太多 - 在此实现中模型似乎过于紧密耦合。
  2. 模型中的方法有两种一般类型:“getter/setter”和我用来调用“流程方法”的方法,管理流程的方法,调用模型中的其他方法或其他适当的模型 - 这些方法似乎' un-model-like',因为缺乏更好的描述。

实现两种模型是否合适 - “数据/对象模型”(主要填充“getter/setter”,也许是简单的“流程方法”,它们完全是内部的和“流程模型”(填充有“流程方法”,其中需要多个(“数据/对象”)模型的协作)?

在这个实现中,我们有代表“用户”、“产品”、“订单”以及“注册”、“订单”等的模型。

想法?

4

3 回答 3

1

这个问题的解决方案是在模型之上有一个单独的层,一个薄层。该层有时称为服务层或应用层。这一层并没有过多的状态,而是调用了各种模型方法和数据访问方法。

例如,您可能有一个用于管理订单的服务类。

class OrderService {

placeOrder(Order order) {
   order.doModelStuff();
   orderDao.save(order);

}

removeOrder(order){
    order.cancel();
    orderDao.delete(order);

...
}

或者

class UserService {

registerUser(User user) {
    if(userDao.userExists(user)) {
       throw exception: user exists;
    } 
    user.doRegistrationStuff();
    userDao.save(user);
}

服务层中的方法并不局限于操作单个实体。通常,他们可以访问和操作多个模型。例如,

placeOrder(Customer customer, Order order) {
     customer.placeOrder(order);
     save customer, if necessary.
     save order, if necessary
     customer.sendEmail();
     Shipper shipper = new shipper;
     shipper.ship(order, customer.getAddress());
     ...

}

这一层的想法是,它的方法做一个工作单元(通常对应于一个用例)。这实际上更多的是程序性质。您可以从 Martin Fowler 和其他人那里了解有关该层的更多信息。

注意:我的意思是展示什么是服务/应用层,而不是展示订单、客户等的实现。

于 2012-11-29T16:52:45.413 回答
0

Martin Fowler 在他的“重构”一书中似乎认为,由数据、访问器和其他任何东西组成的“数据”模型是重构为另一个类的良好候选者。他在他的代码“难闻气味”库中称其为“数据类”。

这表明,简化不同流程之间的交互可能会更好,但允许流程与自己的数据紧密耦合

例如,PlaceOrder 和 OrderData 可以紧密耦合,但 PlaceOrder 涉及最少的交互,例如与客户流程的 AddOrderToCustomerRecord。

于 2012-11-29T16:46:47.570 回答
0

在设计模式术语中,将您的模型对象分离为简单对象(使用 getter 和 setter)和流程对象(使用流程逻辑)会将您的领域模型变成带有事务脚本的贫血领域模型。

你不想那样做。模型对象告诉对方做事(你的过程方法)是好的。这种耦合比使用 getter 和 setter 获得的耦合更可取。

对象必须相互交互,因此必须存在某种程度的耦合。如果您将这种耦合限制为旨在向外界公开的方法(如果您愿意,可以使用对象的 API),您可以更改对象的实现而不会产生副作用。

一旦公开了实现细节(getter 和 setter 公开了对象内部,它们是特定于实现的),就不能在没有副作用的情况下更改实现。那是糟糕的耦合。有关更详尽的解释,请参阅Getter 和 Setter Are Evil 。

回到你的过程方法和过度耦合,有一些方法可以减少模型对象之间的耦合。查看得墨忒耳法则,了解什么是合理的,什么应该是危险信号。

还可以查看Domain Driven Design以了解减少耦合的模式。像聚合根这样的东西可以减少耦合和复杂性。

tl;dr 版本:不要分离你的数据和方法,隐藏你的数据,只公开你的 API。

于 2012-11-29T17:21:27.753 回答