【问题标题】:Model-Service decoupling: what if my model needs a service?模型-服务解耦:如果我的模型需要服务怎么办?
【发布时间】:2012-11-11 17:34:35
【问题描述】:

服务层应该位于模型层之上。因此,模型不应该调用服务。

但是,我正面临一种情况,例如:

interface Component {
    getResult();
}
class Number implements Component {
    private value;
    public getResult() {
        return value;
    }
}
class Addition implements Component {
    private component1;
    private component2;
    public getResult() {
        return component1->getResult() + component2->getResult();
    }
}
class ConstantFromExternalSource implements Component {
    private identifier;
    public getResult() {
        // call a service for fetching constant identified by identifier
    }
}

(伪代码)

这里,我的模型需要通过服务(无论是否为 web 服务)访问外部数据源。

在这种情况下我应该怎么做? 可以在模型中调用服务吗?

如果您建议从模型中移走“getResult”方法并将其放入“ComponentService”中,我会不同意,因为这样我会失去 OOP 的所有优点(这里我的模型创建了一棵树,需要递归解决,所以OOP是最好的解决方案)。

【问题讨论】:

    标签: oop service model domain-driven-design soa


    【解决方案1】:

    模型中调用服务可以吗?

    取决于什么样的服务。就 DDD 而言,

    • 域绝对不应该知道使用域的底层应用程序层服务。

    • 层服务不是什么大问题,因为它们是同一层的一部分。

    • 相比之下,Infrastructure 层服务必须注入到您的域对象中,并且如果您希望域和基础设施之间的松散耦合(与存储库接口/实现)。 Sergey 对此有很好的实现。

    【讨论】:

      【解决方案2】:

      您可以通过多种方式实现这一目标。 首先,您可以在单独的界面中提取模型的依赖项,例如:

      interface CustomService {
       getResult();
      }
      
      class ExternalService implments CustomService 
      {
        getResult() { // access web service }
      }
      

      然后将该依赖注入到模型中:

      class ConstantFromExternalSource implements Component {
          private identifier;
          private CustomService service;
      
          ConstantFromExternalSource(CustomService service)
          {
              this.service = service;
          }
      
      
          public getResult() {
              // call a service for fetching constant identified by identifier
              return service.getResult();
          }
      }
      

      实现此目的的另一种方法是使用Observer Design Pattern 并通知更高级别的抽象您需要它们提供的东西。

      在这两种方式中,您都可以将模型与服务层的具体实现分离。

      【讨论】:

      • 感谢您的回答,但我认为您没有直接回答问题(或者我错了吗?)。你是说从领域模型内部调用外部服务可以吗?
      • 直接调用外部服务是一个糟糕的决定,但通过抽象接口调用它 - 绝对可以。在这种情况下,我们可以将此服务视为“服务层”抽象,在可维护性、可读性或任何其他设计原则方面没有任何缺点。
      • 当然!精彩的!抱歉,我一开始没有得到使用接口或使用实现之间的“微妙”区别。现在我只需要在我的域层中创建一个接口,从我的模型中调用它,并将 web 服务的实现设置为要使用的实现。谢谢!
      • @Matthieu:是的,你完全正确。这将导致更少的耦合设计,因为模型依赖于抽象而不是实现。
      • 最后一个问题,如果模型可以直接调用域服务,并且给定存储库域服务,模型可以调用存储库吗?我认为不应该是这样:我们应该使用聚合,并通过对象之间的关联在对象的图形中移动
      【解决方案3】:

      我会让外部源直接将常量作为组件返回。我不会将 ConstantFromExtenralSource 类与服务耦合,甚至不会作为接口,因为该类(至少在这种形式中)除了调用服务之外什么都不做。

      但是,如果外部源返回一些需要包装在 ConstrantFromExternalSource 类中的数据,我只需通过构造函数将数据推送到对象中。

      简而言之,如果模型只是从外部源获取数据的抽象,只需使用存储库来实际获取数据并返回模型,如果外部源不会直接返回您需要的对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-15
        • 1970-01-01
        • 2013-09-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多