仕様パターン

UMLの仕様パターン

コンピュータプログラミングにおいて、仕様パターンとは、ブール論理を用いてビジネスルールを連鎖させることでビジネスルールを再結合できる特定のソフトウェア設計パターンです。このパターンは、ドメイン駆動設計の文脈で頻繁に使用されます

仕様パターンは、他のビジネスルールと組み合わせ可能なビジネスルールを概説します。このパターンでは、ビジネスロジックのユニットは、抽象集約クラスであるComposite Specificationクラスから機能を継承します。Composite Specificationクラスには、ブール値を返すIsSatisfiedByという関数が1つあります。インスタンス化後、仕様は他の仕様と「連鎖」されるため、新しい仕様は容易に保守できるだけでなく、ビジネスロジックを高度にカスタマイズできます。さらに、インスタンス化時に、ビジネスロジックはメソッド呼び出しや制御の反転によって状態を変更し、永続化リポジトリなどの他のクラスの委任先となることができます。

高レベルのビジネス/ドメイン ロジックの実行時合成を実行する結果として、仕様パターンは、アドホックなユーザー検索基準をリポジトリによって処理される低レベルのロジックに変換するための便利なツールになります。

仕様はロジックを再利用可能な形式でカプセル化したものであるため、徹底的にユニット テストを実行するのは非常に簡単です。また、このコンテキストで使用する場合は、Humble Object パターンの実装にもなります。

コード例

C#

パブリックインターフェイスISpecification { bool IsSatisfiedBy (オブジェクト候補); ISpecification And ( ISpecificationその他); ISpecification AndNot ( ISpecificationその他); ISpecification Or ( ISpecificationその他); ISpecification OrNot ( ISpecificationその他); ISpecification Not (); }                   パブリック抽象クラスCompositeSpecification : ISpecification {パブリック抽象bool IsSatisfiedBy (オブジェクト候補);            パブリックISpecification And ( ISpecification other ) {新しいAndSpecification ( this other )を返します。 }           パブリックISpecification AndNot ( ISpecification other ) {新しいAndNotSpecification ( this other )を返します。 }           パブリックISpecification Or ( ISpecification other ) {新しいOrSpecification ( this other )を返します。 }           パブリックISpecification OrNot ( ISpecification other ) {新しいOrNotSpecification ( this other )を返します。 }           パブリックISpecification Not () {新しいNotSpecification ( this )を返します。 } }        パブリッククラスAndSpecification : CompositeSpecification {プライベートISpecification _leftCondition ;プライベートISpecification _rightCondition ;            パブリックAndSpecification ( ISpecificationISpecification) { _leftCondition =; _rightCondition =; }              public override bool IsSatisfiedBy (オブジェクト候補) { return _leftCondition.IsSatisfiedBy (候補) && _rightCondition.IsSatisfiedBy (候補) ; } }           パブリッククラスAndNotSpecification : CompositeSpecification {プライベートISpecification _leftCondition ;プライベートISpecification _rightCondition ;            パブリックAndNotSpecification ( ISpecificationISpecification) { _leftCondition =; _rightCondition =; }              public override bool IsSatisfiedBy (オブジェクト候補) { return _leftCondition.IsSatisfiedBy (候補) && _rightCondition.IsSatisfiedBy (候補) ! = true ; } }             パブリッククラスOrSpecification : CompositeSpecification {プライベートISpecification _leftCondition ;プライベートISpecification _rightCondition ;           パブリックOrSpecification ( ISpecificationISpecification) { _leftCondition =; _rightCondition =; }              public override bool IsSatisfiedBy (オブジェクト候補) { return _leftCondition.IsSatisfiedBy (候補) || _rightCondition.IsSatisfiedBy (候補) ; } }           パブリッククラスOrNotSpecification : CompositeSpecification {プライベートISpecification _leftCondition ;プライベートISpecification _rightCondition ;           パブリックOrNotSpecification ( ISpecificationISpecification) { _leftCondition =; _rightCondition =; }              public override bool IsSatisfiedBy (オブジェクト候補) { return _leftCondition.IsSatisfiedBy (候補) || _rightCondition.IsSatisfiedBy (候補) ! = true ; } }             パブリッククラスNotSpecification : CompositeSpecification {プライベートISpecification _wrapped ;         パブリックNotSpecification ( ISpecification x ) { _wrapped = x ; }         public override bool IsSatisfiedBy (オブジェクト候補) { return ! _wrapped . IsSatisfiedBy (候補); } }         

ジェネリックを使用した C# 6.0

パブリックインターフェイスISpecification < T > { bool IsSatisfiedBy ( T candidate ); ISpecification < T > And ( ISpecification < T > other ); ISpecification < T > AndNot ( ISpecification < T > other ); ISpecification < T > Or ( ISpecification < T > other ); ISpecification < T > OrNot ( ISpecification < T > other ); ISpecification < T > Not (); }                   パブリック抽象クラスLinqSpecification < T > : CompositeSpecification < T > {パブリック抽象Expression < Func < T , bool >> AsExpression ();パブリックオーバーライドbool IsSatisfiedBy ( T candidate ) => AsExpression (). Compile ()( candidate ); }                 パブリック抽象クラスCompositeSpecification < T > : ISpecification < T > {パブリック抽象bool IsSatisfiedBy ( T candidate );パブリックISpecification < T > And ( ISpecification < T > other ) =>新しいAndSpecification < T > ( this other );パブリックISpecification < T > AndNot ( ISpecification < T > other ) =>新しいAndNotSpecification < T > ( this other );パブリックISpecification < T > Or ( ISpecification < T > other ) =>新しいOrSpecification < T > ( this other );パブリックISpecification < T > OrNot ( ISpecification < T > other ) =>新しいOrNotSpecification < T > ( this other );パブリックISpecification < T > Not () =>新しいNotSpecification < T > ( this ); }                                                パブリッククラスAndSpecification < T > : CompositeSpecification < T > {プライベートISpecification < T > _left ;プライベートISpecification < T > _right ;           パブリックAndSpecification ( ISpecification < T >ISpecification < T >) { _left =; _right =; }             パブリックオーバーライドbool IsSatisfiedBy ( T候補) = > _left.IsSatisfiedBy (候補) && _right.IsSatisfiedBy (候補) ; }        パブリッククラスAndNotSpecification < T > : CompositeSpecification < T > {プライベートISpecification < T > _left ;プライベートISpecification < T > _right ;           パブリックAndNotSpecification ( ISpecification < T >ISpecification < T >) { _left =; _right =; }             public override bool IsSatisfiedBy ( T候補) = > _left.IsSatisfiedBy (候補) && ! _right.IsSatisfiedBy (候補) ; }        パブリッククラスOrSpecification < T > : CompositeSpecification < T > {プライベートISpecification < T > _left ;プライベートISpecification < T > _right ;           パブリックOrSpecification ( ISpecification < T >ISpecification < T >) { _left =; _right =; }             public override bool IsSatisfiedBy ( T candidate ) = > _left.IsSatisfiedBy ( candidate ) || _right.IsSatisfiedBy ( candidate ) ; } public class OrNotSpecification < T > : CompositeSpecification < T > { private ISpecification < T > _left ; private ISpecification < T > _right ;                   パブリックOrNotSpecification ( ISpecification < T >ISpecification < T >) { _left =; _right =; }             public override bool IsSatisfiedBy ( T候補) = > _left.IsSatisfiedBy (候補) || ! _right.IsSatisfiedBy (候補) ; }        パブリッククラスNotSpecification < T > : CompositeSpecification < T > { ISpecification < T > other ;パブリックNotSpecification ( ISpecification < T > other ) => this . other = other ;パブリックオーバーライドbool IsSatisfiedBy ( T candidate ) => ! other . IsSatisfiedBy ( candidate ); }                    

パイソン

abcからABCをインポートabstractmethodからdataclassesインポート、 typeからAnyをインポート          クラスBaseSpecification ( ABC ): @abstractmethod def is_satisfied_by ( self , candidate : Any ) -> bool : NotImplementedError ()を発生させます           def __call__ ( self , candidate : Any ) - > bool : self.is_satisfied_by ( candidate )返します        def __and__ ( self , other : "BaseSpecification" ) -> "AndSpecification" : return AndSpecification ( self , other )         def __or__ ( self , other : "BaseSpecification" ) -> "OrSpecification" : return OrSpecification ( self , other )         def __neg__ ( self ) -> "NotSpecification" : return NotSpecification ( self )     @dataclass ( frozen = True )クラスAndSpecification ( BaseSpecification ):最初: BaseSpecification 2番目: BaseSpecification      def is_satisfied_by ( self , candidate : Any ) - > bool : self.first.is_satisfied_by ( candidate )self.second.is_satisfied_by ( candidate )返します         @dataclass ( frozen = True )クラスOrSpecification ( BaseSpecification ):最初: BaseSpecification 2 番目: BaseSpecification      def is_satisfied_by ( self , candidate : Any ) - > bool : self.first.is_satisfied_by ( candidate )またはself.second.is_satisfied_by ( candidate )返します         @dataclass ( frozen = True )クラスNotSpecification ( BaseSpecification ):対象: BaseSpecification    def is_satisfied_by ( self , candidate : Any ) - > bool : self.subject.is_satisfied_by ( candidate )ないを返す        

C++

テンプレート< class T > class ISpecification { public : virtual ~ ISpecification () = default ; virtual bool IsSatisfiedBy ( T Candidate ) const = 0 ; virtual ISpecification < T >* And ( const ISpecification < T >& Other ) const = 0 ; virtual ISpecification < T >* AndNot ( const ISpecification < T >& Other ) const = 0 ; virtual ISpecification < T >* Or ( const ISpecification < T >& Other ) const = 0 ; virtual ISpecification < T >* OrNot ( const ISpecification < T >& Other ) const = 0 ; virtual ISpecification < T >* Not () const = 0 ; };                                             テンプレート< class T >クラスCompositeSpecification : public ISpecification < T > { public : virtual bool IsSatisfiedBy ( T Candidate ) const override = 0 ;             仮想ISpecification < T >* And ( const ISpecification < T >& Other ) const override ;仮想ISpecification < T >* AndNot ( const ISpecification < T >& Other ) const override ;仮想ISpecification < T >* Or ( const ISpecification < T >& Other ) const override ;仮想ISpecification < T >* OrNot ( const ISpecification < T >& Other ) const override ;仮想ISpecification < T >* Not () const override ; };                            テンプレート< class T >クラスAndSpecification final : public CompositeSpecification <T> { public : const ISpecification <T> & Left ; const ISpecification <T> & Right ;           AndSpecification ( const ISpecification < T >& InLeft const ISpecification < T >& InRight ) : Left ( InLeft )、Right ( InRight ) { }         virtual bool IsSatisfiedBy ( T Candidate ) const override { return Left.IsSatisfiedBy ( Candidate ) && Right.IsSatisfiedBy ( Candidate ) ; } } ;        テンプレート< class T > ISpecification < T >* CompositeSpecification < T >:: And ( const ISpecification < T >& Other ) const { return new AndSpecification < T > ( * this , Other ); }         テンプレート< class T > class AndNotSpecification final : public CompositeSpecification < T > { public : const ISpecification < T >& Left ; const ISpecification < T >& Right ;           AndNotSpecification ( const ISpecification < T >& InLeft const ISpecification < T >& InRight ) : Left ( InLeft )、Right ( InRight ) { }         virtual bool IsSatisfiedBy ( T Candidate ) const override { return Left.IsSatisfiedBy ( Candidate ) && ! Right.IsSatisfiedBy ( Candidate ) ; } } ;        テンプレート< class T > class OrSpecification final : public CompositeSpecification < T > { public : const ISpecification < T >& Left ; const ISpecification < T >& Right ;           OrSpecification ( const ISpecification < T >& InLeft const ISpecification < T >& InRight ) : Left ( InLeft )、Right ( InRight ) { }         virtual bool IsSatisfiedBy ( T Candidate ) const override { return Left.IsSatisfiedBy ( Candidate ) || Right.IsSatisfiedBy ( Candidate ) ; } } ;        テンプレート< class T > class OrNotSpecification final : public CompositeSpecification < T > { public : const ISpecification < T >& Left ; const ISpecification < T >& Right ;           OrNotSpecification ( const ISpecification < T >& InLeft const ISpecification < T >& InRight ) : Left ( InLeft )、Right ( InRight ) { }         virtual bool IsSatisfiedBy ( T Candidate ) const override { return Left.IsSatisfiedBy ( Candidate ) || ! Right.IsSatisfiedBy ( Candidate ) ; } } ;        テンプレート< class T >クラスNotSpecification final : public CompositeSpecification < T > { public : const ISpecification < T >& Other ;         NotSpecification ( const ISpecification < T >& InOther ) : Other ( InOther ) { }     virtual bool IsSatisfiedBy ( T Candidate ) const override { return ! Other.IsSatisfiedBy ( Candidate ) ; } } ;      テンプレート< class T > ISpecification < T >* CompositeSpecification < T >:: AndNot ( const ISpecification < T >& Other ) const { return new AndNotSpecification < T > ( * this , Other ); }         テンプレート< class T > ISpecification < T >* CompositeSpecification < T >:: Or ( const ISpecification < T >& Other ) const { return new OrSpecification < T > ( * this , Other ); }         テンプレート< class T > ISpecification < T >* CompositeSpecification < T >:: OrNot ( const ISpecification < T >& Other ) const { return new OrNotSpecification < T > ( * this , Other ); }         テンプレート< class T > ISpecification < T >* CompositeSpecification < T >:: Not () const { return new NotSpecification < T > ( * this ); }      

タイプスクリプト

エクスポートインターフェイスISpecification { isSatisfiedBy ( candidate : unknown ) : boolean ; and ( other : ISpecification ) : ISpecification ; andNot ( other : ISpecification ) : ISpecification ; or ( other : ISpecification ) : ISpecification ; orNot ( other : ISpecification ) : ISpecification ; not ( ) : ISpecification ; }                    エクスポート抽象クラスCompositeSpecification はISpecificationを実装します{ abstract isSatisfiedBy ( candidate : unknown ) : boolean ;           and ( other : ISpecification ) : ISpecification {新しいAndSpecification ( this other )を返します。 }         andNot ( other : ISpecification ) : ISpecification {新しいAndNotSpecification ( this other )を返します。 }         または( other : ISpecification ) : ISpecification {新しいOrSpecification ( this other )を返します。 }         orNot ( other : ISpecification ) : ISpecification {新しいOrNotSpecification ( this other )を返します。 }         not () : ISpecification {新しいNotSpecification ( this )を返します。 } }      エクスポートクラスAndSpecificationはCompositeSpecificationを拡張します{コンストラクター( private leftCondition : ISpecification private rightCondition : ISpecification ) { super (); }               isSatisfiedBy (候補:不明) : boolean {これを返します左の状態isSatisfiedBy (候補) && this 右の状態isSatisfiedBy (候補者); } }        エクスポートクラスAndNotSpecificationはCompositeSpecificationを拡張します{コンストラクター( private leftCondition : ISpecification private rightCondition : ISpecification ) { super (); }               isSatisfiedBy (候補:不明) : boolean {これを返します左の状態isSatisfiedBy (候補) && this 右の状態isSatisfiedBy (候補) !== true ; } }          エクスポートクラスOrSpecificationはCompositeSpecificationを拡張します{コンストラクター( private leftCondition : ISpecification private rightCondition : ISpecification ) { super (); }               isSatisfiedBy (候補:不明) : boolean {これを返します左の状態isSatisfiedBy (候補) ||これ右の状態isSatisfiedBy (候補者); } }        エクスポートクラスOrNotSpecificationはCompositeSpecificationを拡張します{コンストラクター( private leftCondition : ISpecification private rightCondition : ISpecification ) { super (); }               isSatisfiedBy (候補:不明) : boolean {これを返します左の状態isSatisfiedBy (候補) ||これ右の状態isSatisfiedBy (候補) !== true ; } }          エクスポートクラスNotSpecificationはCompositeSpecificationを拡張します{コンストラクター(プライベートラップ: ISpecification ) { super (); }            isSatisfiedBy (候補:不明) :ブール値{ return ! this . wrapper . isSatisfiedBy (候補); } }      

使用例

次の例では、次の場合に請求書が取得され、回収会社に送信されます。

  1. 期限が過ぎている、
  2. 通知が送信され、
  3. 彼らはまだ債権回収会社に所属していません。

この例は、ロジックがどのように連鎖されているかの結果を示すことを目的としています。

この使用例では、OverdueSpecification請求書の支払期限が30日以上経過した場合に満たされるクラス、NoticeSentSpecification顧客に3通の通知が送信された場合に満たされるクラス、そしてInCollectionSpecification請求書が既に回収業者に送付された場合に満たされるクラスが事前に定義されていることを前提としています。これらのクラスの実装はここでは重要ではありません。

SendToCollectionこれら 3 つの仕様を使用して、請求書の支払期限が過ぎ、通知が顧客に送信され、まだ回収機関に届いていない場合に満たされる、という新しい仕様を作成しました。

var overdue =新しいOverdueSpecification (); var noticeSent =新しいNoticeSentSpecification (); var inCollection =新しいInCollectionSpecification ();            // 仕様パターンのロジック連鎖の例var sendToCollection = overdue . And ( noticeSent ). And ( inCollection . Not ());   var請求書= InvoiceService . GetInvoices ();   foreach ( var invoice in請求書) { if ( sendToCollection . IsSatisfiedBy (請求書)) { invoice . SendToCollection (); } }         

参考文献

  • エヴァンス、エリック (2004).ドメイン駆動設計. Addison-Wesley. p. 224.
  • Eric EvansとMartin Fowlerによる仕様
  • 仕様パターン入門(マット・バーサー著)
  • 仕様パターン: VB.Net を使った 4 部構成の入門書 (Richard Dalton 著)
  • PHP の仕様パターン (Moshe Brevda 著)
  • HappyrによるPHPのHappyr Doctrine仕様
  • Simon Strandgaard 著「Swift の仕様パターン」
  • TypeScript と JavaScript の仕様パターン (Thiago Delgado Pinto 著)
  • Rolf VreijdenbergerによるFlash ActionScript 3の仕様パターン
「https://en.wikipedia.org/w/index.php?title=Specification_pattern&oldid=1312009825」から取得