SPECIFICATION 背后的主要思想是它是一个谓词,这通常意味着使用逻辑运算符
规范是对既定形式主义的改编(Eric Evans DDD,第 274 页)
例如,我们可以说盒子是红色的,即满足一些 RedSpecification。我们可以声明一些 GreenSpecification,甚至是复合 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 模式的变体,但其主要目的是封装业务规则是某种声明形式。
从技术上讲 - 它并不总是 STRATEGY 的直接实现 - 在第一阶段它可以只是一个单独的类(如蓝皮书的第一章所示),但它可以在以后轻松扩展
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 只描述对象的属性(这些属性可以满足或不满足业务需求)。当然,某些验证 POLICY 可以使用 SPECIFICATION 来检查要求是否得到满足。
因此,您的项目中可以有许多不同的 SPECIFICATION 实例,它们可以从业务角度描述有效和无效的对象。实际上,规范根本没有意义:例如,如果您有一个产品搜索站点,用户可以指定一个请求来搜索名为“XBOX”的产品,但供应商名称为“Sony”,如果知道只有特定供应商可以生产的特定产品未包含在您的模型中。
POLICY 的重要方面是它的意图是封装实际的业务规则(因此代码不会分散在项目的不同部分),因此当规则发生变化时,您可以轻松找到相应的类。因此,您的项目中可以有许多 SPECIFICATION,但 POLICIES 的数量是可管理的,并且这些 POLICIES 应该很容易找到和更改。
PS请注意,这篇文章只是一个例子,并不是过度设计的许可,当然你应该使用最简单的设计,这是常识。