8

私は現在、ドメイン層からデータベースを完全に抽象化する Data Mappers を使用するアプリケーションの書き直しに取り組んでいます。ただし、 Domain オブジェクト間の関係を処理するためのより良いアプローチはどれか疑問に思っています。

  1. 関連するデータ マッパーから必要な find() メソッドをドメイン オブジェクト内で直接呼び出します。
  2. リレーションシップ ロジックをネイティブ データ マッパーに記述し (これは、例が PoEAA で行う傾向にあります)、ドメイン オブジェクト内でネイティブ データ マッパー関数を呼び出します。

「Fat Model、Skinny Controller」というマントラを維持するために、ドメインオブジェクトはデータマッパーを認識している必要があるように思えます(それが独自のものであるか、システム内の他のマッパーにアクセスできるかどうか)。 . さらに、オプション 2 は、単一のデータ マッパーに限定するのではなく、複数のデータ マッパーにまたがるテーブル アクセス ロジックを作成するため、データ アクセス レイヤーを不必要に複雑にしているようです。

では、ドメイン オブジェクトに関連するデータ マッパーを認識させ、ドメイン オブジェクトから直接データ マッパー関数を呼び出すのは正しくないのでしょうか?

更新:これらは、ドメイン オブジェクト間の関係の問題を処理するために思い描くことができる唯一の 2 つのソリューションです。より良い方法を示す例は大歓迎です。

4

4 に答える 4

7

残念ながら、Repository パターンの意図を少し誤解しています。

リポジトリは、特定のドメイン オブジェクト (通常は集約ルート) のメモリ内コレクションのように動作することを意図しています。

interface EmployeeRepository
{
    List<Employee> retrieveBy(Criteria someCriteria);
    void store(Employee someEmployee);
    int countOf(Criteria someCriteria);
    // convenience methods
    Employee retrieveById(String id);
    Employee retrieveBySSN(String ssn);
}

このコードのクライアントは、単体テストの場合のように、コレクションがメモリ内にあるかどうか、場合によっては ORM マッパーと通信するか、他の場所でストアド プロシージャを呼び出すか、特定のドメイン オブジェクトのキャッシュを維持するかを認識しません。 .

これはまだあなたの質問に答えていません。実際、適切なリポジトリにデリゲートする save() および load() メソッドをドメイン オブジェクトに含めることができます。永続性がビジネス ドメインの一部になることはほとんどなく、ドメイン オブジェクトを変更する理由が複数あるため、これは正しい方法ではないと思います。

とりとめのないものについては、この関連する質問を確認してください。

この回答に関するいくつかのコメントへの回答:

正当な批判。ただし、既存のドメイン オブジェクトのコンテキスト内で単一のドメイン オブジェクトまたは関連するドメイン オブジェクトのコレクションを取得する方法については、まだ混乱しています。–ガブリエル1836

従業員が多くのスキルを持っているとしましょう。次のように従業員リポジトリがスキル リポジトリを呼び出しても問題はないと思います。

// assume EmployeeRepository talks to a DB via sprocs
public Employee retrieveById(String id)
{
    ResultSet employeeResultSet = this.database.callSproc("PROC_GetEmployeeById", 
        new Object[] { id });

    List<Skill> skills = 
        new SkillRepository().retrieveBy(new EqualsCriteria("EmployeeId", id));

    Employee reconstructed = new EmployeeFactory().createNew().
                                  fromResultSet(employeeResultSet).
                                  withSkills(skills).
                                  build();

    return reconstructed;    
}

もう 1 つの方法は、スキル リポジトリを呼び出す代わりに、従業員リポジトリに、この例ではストアド プロシージャを呼び出してスキルの結果セットをロードさせ、次にスキル ファクトリに委任してスキルのリストを取得させることです。

リポジトリを呼び出すことはできませんか? データ マッパーへの呼び出しを発行するか、オブジェクトをメモリ内にロードするかは問題ですよね? –ガブリエル1836

その通りです。私は通常、単体テストでデータ層全体をこの方法でモックアウトします。

于 2009-01-22T22:23:00.157 に答える
7

はい。なぜドメインオブジェクトがそのようなことを知っているのでしょうか? 理由でさえありませんが、どのように?DAL を Domain オブジェクトに挿入しますか?

ドメインは SRP に従う必要があり、それ以外はすべて有効です。ドメインをトラバースするとき、それらのプロパティが遅延読み込みによって設定されたものなのか、インスタンス化からハイドレートされたものなのかを認識しない必要があります。

DAL オブジェクトを含むドメイン モデルを作成しましたが、維持するのは悪夢でした。次に、NHibernate を学び、私のドメインは、カプセル化したい POCO とそれぞれのビジネス ロジックで構成されています。

[編集]

詳細はこちら。説明しようとしても恥ずかしくなるだけです。ユーザーとしての実装についてしか話せません。これは、ドメイン モデルの管理に関する優れた記事です。あなたが興味を持っているのは、インターセプターとミックスインの実装です。

これらのツールを使用すると、次のように従業員クラスを作成できます。

public class Employee
{
    public Employee()
    {
        Skills = new List<Skill>();
    }

    public string Name { get; set; }
    public IList<Skill> Skills { get; private set; }

    public void AddSkill(Skill skill)
    {
        // Perform Domain specific validation here...

        Skills.Add(skill);
    }
}

ご覧のとおり、私のデータ アクセスのニーズは、私のドメインの設計にはまったく影響しません。

于 2009-01-22T04:19:44.023 に答える
0

私は同意しません。ドメインオブジェクトはAbstractFactoryを介してリポジトリにアクセスできると思います。

public class Client
{
  public void ChangeZipCode(string zipCode)
  {
    // This method access memory or database depending on the factory context
    bool zipCodeExists = RepositoryFactory.Get<IZipCode>().Exists(zipCode);
    this.zipCode = zipCode;
  }
}

このパターンを使用することにより、コード全体にリポジトリインターフェイスを挿入する必要はなく、リポジトリファクトリのみを挿入する必要があります。

public abstract class RepositoryFactory
{
  // Class operations
  private static _globalInstance;
  public static CreateGlobalInstance(RepositoryFactory factory)
  {
    _glocalInstance = factory;
  }
  public static I Get<I>()
  {
    return _globalInstance.Get<I>();
  }
  /////////////////////

  ///// this operation should be inherited by:
  ///// * NHibernateRepositoryFactory //
  ///// * Linq2SqlRepositoryFactory ////
  ///// * NUnitRepositoryFactory ///////      
  ///// it depends in your context ////////////////////////
  public abstract I GetRepository<I>();
}

私はユニットテストで何の問題もなくそれを何年もやっています。

したがって、依存性注入はこのクラスRepositoryFactoryでのみ必要です。

于 2010-05-06T14:55:23.843 に答える
0

適切なパターンをさらに読んで検索した後、Repository Patternに出くわしました。

私が見る限り、これはまさに、ドメイン オブジェクトとデータ マッパーを完全に抽象化したまま、パーソンなどのドメイン オブジェクトがクエリを適切なデータ マッパーに適切に委任できるようにする想定されたソリューションです。

于 2009-01-22T17:09:26.327 に答える