8

それで、私はここで仕様パターンに関するいくつかの投稿を見ましたが、これに対する答えはまだ見つかりませんでした。

私の質問は、n層アーキテクチャでは、仕様を正確にどこで「更新」する必要があるのか​​ということです。

  1. それらをサービス層(別名、アプリケーション層と呼ばれることもあります...基本的には.aspxコードビハインドが通信するもの)に配置することはできますが、そうすることで、ビジネスルールを漏らしてしまうような気がします。ドメイン。ドメインオブジェクトが(サービスレイヤー以外の)他の方法でアクセスされる場合、ドメインオブジェクトは独自のビジネスルールを適用できません。

  2. コンストラクターインジェクションを介して、仕様をModelクラスにインジェクトでき​​ます。しかし、繰り返しますが、これは「間違っている」と感じます。モデルクラスに注入する必要があるのは、キャッシング、ロギング、ダーティフラグトラッキングなどの「サービス」だけだと思います。それを回避できる場合は、モデルのコンストラクターを散らかす代わりにアスペクトを使用します。大量のサービスインターフェイスを備えたクラス。

  3. メソッドインジェクション(「ダブルディスパッチ」と呼ばれることもあります???)を介して仕様を注入し、そのメソッドに注入された仕様を明示的にカプセル化して、ビジネスルールを適用することができます。

  4. 「ドメインサービス」クラスを作成します。このクラスは、コンストラクターインジェクションを介して仕様を取得し、サービスレイヤーがドメインサービスを使用してドメインオブジェクトを調整できるようにします。仕様によって適用されるルールはまだ「ドメイン」にあり、ドメインサービスクラスは、調整しているドメインオブジェクトと非常によく似た名前を付けることができるため、これは私には問題ないようです。ここで重要なのは、仕様パターンを「適切に」実装するためだけに、たくさんのクラスとコードを書いているような気がすることです。

これに加えて、問題の仕様は、それが「満たされている」かどうかを判断するためにリポジトリを必要とします。

これにより、特にパフォーマンスの問題が発生する可能性があります。コンストラクタインジェクションを使用する場合、b / cを消費するコードは、おそらく仕様をラップするプロパティを呼び出す可能性があり、それがデータベースを呼び出します。

それで、何かアイデア/考え/記事へのリンクはありますか?

仕様を更新して使用するのに最適な場所はどこですか?

4

2 に答える 2

8

仕様は、ビジネスルールの実装チェックです。ドメインレイヤーの終止符に存在する必要があります。

すべてのコードベースが異なるため、これをどのように行うかについて具体的に説明するのは難しいですが、私の意見では、ビジネスロジックはドメインレイヤーにある必要があり、他の場所にはない必要があります。このビジネスロジックは、完全にテスト可能であり、UI、データベース、外部サービス、およびその他の非ドメイン依存関係から緩く結合されている必要があります。したがって、上記の1、2、および3は完全に除外します。

4はオプションであり、少なくとも仕様はドメインレイヤーに存在します。ただし、仕様の更新は、実際には実装に依存します。通常、依存関係インジェクションを使用するため、ほとんどすべてのオブジェクトの更新は、IOCコンテナーと対応するブートストラップコードを介して実行されます(つまり、通常、アプリケーションを流暢に配線します)。ただし、ビジネスロジックをUIモデルクラスなどに直接リンクすることは決してありません。通常、UIとドメインなどの間に輪郭/境界があります。通常、ドメインサービスコントラクトを定義します。これは、UIなどの外部レイヤーで使用できます。

最後に、私の答えは、作業しているシステムが少なくとも何らかの形で複雑であると想定していることです。それが非常に単純なシステムである場合、概念としてのドメイン駆動設計はおそらくやり過ぎです。ただし、私の意見では、コードベースに関係なく、テスト容易性、可読性、SoCなどのいくつかの概念を尊重する必要があります。

于 2011-11-23T11:00:06.897 に答える
8

短い答え:

仕様は主にサービスレイヤーで使用するため、そこにあります。

長い答え: まず、ここに2つの質問があります。

スペックはどこにあり、どこで新しくする必要がありますか?

リポジトリインターフェースと同じように、スペックはドメインレイヤーに存在する必要があります。結局のところ、スペックはドメイン固有です。リポジトリインターフェースでこれを議論するSOに関する質問があります。

しかし、どこで新しくする必要がありますか?さて、私は自分のリポジトリでLinqSpecsを使用しており、ほとんどの場合、リポジトリには3つのメソッドがあります。

public interface ILinqSpecsRepository<T>
{
    IEnumerable<T> FindAll(Specification<T> specification);
    IEnumerable<T> FindAll<TRelated>(Specification<T> specification, Expression<Func<T, TRelated>> fetchExpression);
    T FindOne(Specification<T> specification);
}

残りのクエリは、サービスレイヤーで作成されます。これにより、リポジトリがGetUserByEmail、GetUserById、GetUserByStatusなどのメソッドで肥大化するのを防ぎます。私のサービスでは、仕様を更新して、リポジトリのFindAllメソッドまたはFindOneメソッドに渡します。例えば:

public User GetUserByEmail(string email)
{
    var withEmail = new UserByEmail(email); // the specification
    return userRepository.FindOne(withEmail);
}

そしてここに仕様があります:

public class UserByEmail : Specification<User>
{
    private readonly string email;

    public UserByEmail(string email)
    {
        this.email = email;
    }

    #region Overrides of Specification<User>

    public override Expression<Func<User, bool>> IsSatisfiedBy()
    {
        return x => x.Email == email;
    }

    #endregion
}

だからあなたの質問に答えるために、スペックはサービスレイヤー(私の本の中で)で新しくなりました。

モデルクラスに注入する必要があるのは「サービス」だけだと思います

IMOドメインエンティティに何かを挿入するべきではありません。

これに加えて、問題の仕様は、それが「満たされている」かどうかを判断するためにリポジトリを必要とします。

それはコードの臭いです。そこでコードを確認します。仕様は間違いなくリポジトリを必要とすべきではありません。

于 2011-11-23T15:09:29.677 に答える