Craig Larman 在 Applying UML and Patterns to Object-Oriented Analysis and Design and Iterative Development (2004) 中介绍 GRASP 时讨论了这一点:
在某些情况下,Expert 建议的解决方案是不可取的,通常是因为耦合和内聚方面的问题(这些原则将在本章后面讨论)。
例如,谁应该负责在数据库中保存销售?当然,要保存的大部分信息都在 Sale 对象中,因此专家可以争辩说责任在于 Sale 类。而且,通过这个决定的逻辑扩展,每个类都有自己的服务来将自己保存在数据库中。但是,按照这种推理行事会导致内聚、耦合和重复方面的问题。例如,Sale 类现在必须包含与数据库处理相关的逻辑,例如与 SQL 和 JDBC(Java 数据库连接)相关的逻辑。该课程不再只关注“成为销售”的纯应用逻辑。现在其他种类的责任降低了它的凝聚力。该类必须耦合到另一个子系统的技术数据库服务,例如 JDBC 服务,而不是仅仅耦合到软件对象领域层中的其他对象,所以它的耦合增加了。并且很可能在许多持久类中会重复类似的数据库逻辑。
所有这些问题都表明违反了一个基本的架构原则:设计主要系统关注点的分离。将应用程序逻辑保存在一个地方(例如域软件对象),将数据库逻辑保存在另一个地方(例如单独的持久性服务子系统),等等,而不是将不同的系统关注点混合在同一个组件中。 [11]
支持主要关注点的分离提高了设计中的耦合和内聚。因此,即使 Expert 我们可以找到一些理由将数据库服务的责任放在 Sale 类中,但由于其他原因(通常是内聚和耦合),我们最终会得到一个糟糕的设计。
因此,SRP 通常胜过 Information Expert。
但是,依赖倒置原则可以与 Expert 很好地结合。这里的论点是 Customer 不应该具有 CustomerDTO 的依赖关系(从一般到详细),而是相反。这意味着 CustomerDTO 是专家,并且应该知道如何在给定客户的情况下构建自己:
CustomerDTO dto = new CustomerDTO(bob);
如果你对新的过敏,你可以去静态:
CustomerDTO dto = CustomerDTO.buildFor(bob);
或者,如果你讨厌两者,我们回到 AbstractFactory:
public abstract class DTOFactory<D, E> {
public abstract D createDTO(E entity);
}
public class CustomerDTOFactory extends DTOFactory<CustomerDTO, Customer> {
@Override
public CustomerDTO createDTO(Customer entity) {
return new CustomerDTO(entity);
}
}