【问题标题】:'Process Models' vs 'Data/Object Models' in MVCMVC 中的“流程模型”与“数据/对象模型”
【发布时间】:2012-11-17 17:35:10
【问题描述】:

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

我现有的实现如下所示:

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

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

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

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

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

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

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

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

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

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

想法?

【问题讨论】:

    标签: oop model-view-controller web-applications language-agnostic model


    【解决方案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 和其他人那里了解有关该层的更多信息。

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

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

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

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

        一旦您公开了实现细节(getter 和 setter 公开了对象内部,它们是特定于实现的),您就无法在没有副作用的情况下更改实现。那是糟糕的耦合。请参阅Getters and Setters Are Evil 以获得更详尽的说明。

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

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

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

        【讨论】:

          猜你喜欢
          • 2013-09-18
          • 2022-01-05
          • 2019-07-10
          • 2015-05-25
          • 2016-07-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-18
          相关资源
          最近更新 更多