规范和策略之间的区别?

我正在阅读埃里克·埃文斯(Eric Evans)写的精彩著作《领域驱动设计》(Domain Driven Design)。在他的书中,Eric描述了两个不同的概念:规范模式和策略。

下面是一个规范示例:

public interface ProjectSpecification {
  public boolean isSatisfiedBy(Project p);
}

public class ProjectIsOverdueSpecification implements ProjectSpecification {
  public boolean isSatisfiedBy(Project p) { … }
}

//client:
if {
  (projectIsOverdueSpecification.isSatisfiedBy(theCurrentProject) { … }
}

下面是一个策略示例:

public class CargoBooking {

  private OverBookingPolicy overBookingPolicy = new OverBookingPolicy();

  public int makeBooking(Cargo cargo, Voyage voyage) {
    if (!overbookingPolicy.isAllowed(cargo, voyage)) 
      return –1;
    int confirmation = orderConfirmationSequence.next();
    voyage.addCargo(cargo, confirmation);
    return confirmation;
  }
}

public OverBookingPolicy {
  public boolean isAllowed(Cargo cargo, Voyage voyage) {
    return (cargo.size() + voyage.bookedCargoSize()) <= (voyage.capacity() * 1.1);
  }
}

我知道政策实际上是一种策略,但在上面的两个例子中,绝对没有区别。因此,我现在的问题是:这两种模式之间有什么区别?这两种模式都使业务规则变得明确,那么我们为什么要区分这两种模式呢?对我来说,两者都是谓词。


答案 1

SPECIFICATION背后的主要思想是它是一个谓词,这通常意味着使用它的逻辑运算符

SPECIFICATION是对既定形式主义的改编(Eric Evans DDD,第274页)

例如,我们可以说盒子是红色的,即满足一些红色的规范。我们可以声明一些绿色规范,甚至是复合RedOrGreenSpecification。如果我们有一些支持规范逻辑运算的高级框架,它可以是这样的

BoxSpecification redBoxSpec = BoxSpecification.forColor(BoxColor.RED);
BoxSpecification greenBoxSpec = BoxSpecification.forColor(BoxColor.GREEN);
BoxSpecification redOrGreenBoxSpec = redBoxSpec.or(greenBoxSpec);

然后我们可以使用规范来查询来自某个存储库的所有红色/绿色框:

Collection<Box> boxes = boxRepository.findAll(redOrGreenBoxSpec);

至于 POLICY - 它是 STRATEGY 模式的变体,但它的主要目的是封装业务规则是某种声明性形式。

从技术上讲 - 它并不总是战略的直接实现 - 在第一阶段,它可以只是一个单独的类(如蓝皮书第一章所示),但它可以在以后轻松扩展

策略是设计模式的另一个名称,称为策略 它通常是出于替换不同规则的需要,据我们所知,这里不需要。但是,我们试图捕捉的概念确实符合政策的含义,这在领域驱动设计中同样重要。

例如,我们在一月份将礼物包装在黄色盒子中,在二月份包装在红色盒子中

public class Box{
  public BoxColor getColor(){}
  public void recolor(BoxColor color){} 
}

public class BoxFactory{
    public Box createDefaultBox(SomeDate date){
         NewBoxPolicy boxPolicy = PolicyRegistry.getNewBoxPolicyForDate(date);
         Box box = new Box();
         boxPolicy.prepareBox(box);
         return box;
   }
}
public interface NewBoxPolicy{
   void prepareBox(Box box);
}
public class FebruaryNewBoxPolicy implements NewBoxPolicy{
    public void prepareBox(Box box) { box.recolor(BoxColor.RED}; }
}
public class JanuaryNewBoxPolicy implements NewBoxPolicy{
    public void prepareBox(Box box) { box.recolor(BoxColor.YELLOW}; }
}
public class PolicyRegistry{
   public static NewBoxPolicy getNewBoxPolicyForDate(SomeDate date){
      switch (date.month()){
         case SomeMonth.JANUARY: return JANUARY_NEW_BOX_POLICY;
         case SomeMonth.FEBRUARY: return FEBRUARY_NEW_BOX_POLICY;
         default: throw new AssertionError();
      }
}

重要的是要了解 POLICY 可以封装操作,而 SPECIFICATION 仅描述对象的属性(这些属性既可以满足业务需求,也可以不满足业务需求)。当然,某些验证策略可以使用 SPECIFICATION 来检查是否满足要求。

因此,您可以在项目中拥有许多不同的 SPECIFICATION 实例,并且它们可以从业务角度描述有效和无效的对象。实际上,规格根本就没有意义:例如,如果您有一个产品搜索网站,用户可以指定一个请求来搜索名为“XBOX”的产品,但是使用供应商名称“Sony”,如果只有特定供应商才能生产特定产品的知识在您的模型中没有被捕获。

POLICY的重要方面是它的目的是封装实际的业务规则(因此代码不会分散在项目的不同部分),因此当规则更改时,您可以轻松找到相应的类。因此,您的项目中可以有许多 SPECIFICATIO,但策略数量可管理,这些策略应该易于查找和更改。

P.S.请注意,这篇文章只是一个例子,而不是做过度工程的许可证,当然你应该使用最简单的设计,这是一个常识问题。


答案 2

推荐