34

Eric Evans 著の素晴らしい本 "Domain Driven Design" を読んでいます。Eric は著書の中で、仕様パターンとポリシーという 2 つの異なる概念について説明しています。

仕様の例を次に示します。

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);
  }
}

ポリシーが実際には戦略であることは知っていますが、上記の 2 つの例ではまったく違いはありません。この時点での私の質問は、これら 2 つのパターンの違いは何ですか? どちらのパターンもビジネス ルールを明示的にするのに、なぜこれら 2 つのパターンを区別するのでしょうか? 私にとって、どちらも一種の述語です。

4

1 に答える 1

63

SPECIFICATION の背後にある主な考え方は、それが述語であるということです。これは、多くの場合、論理演算子を使用することを意味します。

SPECIFICATION は、確立された形式主義の適応です (Eric Evans DDD、p. 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 の直接の実装ではありません - 最初の段階では (ブルーブックの最初の章に示されているように) 別のクラスにすることができますが、後で簡単に拡張できます。

ポリシーは、STRATEGY として知られる設計パターンの別の名前です。私たちが知る限り、通常は別のルールを置き換える必要性によって動機付けられますが、ここでは必要ありません。しかし、私たちが捉えようとしている概念は、ポリシーの意味に適合しています。これは、ドメイン駆動設計において同様に重要な動機です。

例えば、1月は黄色い箱に、2月は赤い箱にプレゼントを詰めます。

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 は簡単に見つけて変更できる必要があります。

追伸: この投稿は単なる例であり、オーバーエンジニアリングを許可するものではないことに注意してください。もちろん、可能な限り単純な設計を使用する必要があります。これは常識の問題です。

于 2013-01-06T19:27:00.920 に答える