3

注: 以下の例は C# ですが、この問題は特定の言語に固有のものではありません。

そのため、 S# Architectureのバリアントを使用してオブジェクト ドメインを構築しています。なじみのない人のために、また読む時間を節約するために、永続化レイヤーとの間のロードを担当するドメイン オブジェクトごとに Data Access Object Interface を用意するという単純な考え方があります。特定のオブジェクトをロード/保存するために必要なすべてのものは、そのオブジェクトのデータ アクセス インターフェイスを依存関係として受け入れます。したがって、たとえば、製品が必要に応じて購入した顧客を遅延ロードする次のようにすることができます。

public class Product {
  private ICustomerDao _customerDao;
  private Customer _customer;
  public Product(ICustomerDao customerDao) {_customerDao = customerDao;}
  public int ProductId {get; set;}
  public int CustomerId {get; set;}
  public Customer Customer {
        get{
            if(_customer == null) _customer = _customerDao.GetById(CustomerId);
            return _customer;
        }
}
public interface ICustomerDao {
   public Customer GetById(int id);
}

2 つのオブジェクトが相互にロードできる必要がある状況に到達するまでは、これで問題ありません。たとえば、上記のように、製品がその顧客を遅延読み込みできる必要があるだけでなく、顧客が自分の製品のリストを取得できる必要がある多対 1 の関係です。

public class Customer {
  private IProductDao _productDao;
  private Product[] _products;
  public Customer(IProductDao  productDao) {_productDao = productDao;}
  public int CustomerId {get; set;}
  public Product[] Products {
        get{
            if(_products == null) _products = _productDao. GetAllForCustomer(this);
            return _products;
        }
}


public interface IProductDao {
   public Product[] GetAllForCustomer(Customer customer);
}

これは非常に一般的な状況であることは知っていますが、私はこれに比較的慣れていません。私のつまずきは、データ アクセス オブジェクトを実装するときに何をすべきかということです。Customer は IProductDao に依存しているため、CustomerDao の実装も必要ですが、逆もまた真であり、ProductDao は ICustomerDao に依存する必要があります。

public class CustomerDao : ICustomerDao {
      private IProductDao _productDao;
      public CustomerDao(IProductDao  productDao) {_productDao = productDao;}
      public Customer GetById(int id) {
          Customer c = new Customer(_customerDao);
          // Query the database and fill out CustomerId
          return c;
      }
 }
public class ProductDao : IProductDao {
      private ICustomerDao _customerDao;
      public ProductDao (ICustomerDao customerDao) {_customerDao = customerDao;}
      public Product[] GetAllForCustomer(Customer customer) {
          // you get the idea
      }
 }

そして、ここに問題があります。IProductDao なしで CustomerDao をインスタンス化することはできません。制御コンテナー (Castle Windsor) の反転は、循環依存関係にヒットし、チョークします。

私は、DAOオブジェクト自体を遅延ロードすることを含む当面の解決策を思いつきました(これを回答として投稿します)が、私はそれが好きではありません。この問題に対する定評のある解決策は何ですか?

編集:上記は私が実際に使用しているアーキテクチャを簡略化したものであり、誰かが実際にオブジェクトに DAO を渡すことをお勧めしていません。私が実際に行っていることに近いより良い実装は、実際のオブジェクトが非常に単純で、上記が実際には適切なフィールドを継承してオーバーライドするプロキシ オブジェクトである NHibernate の動作に似ています。

4

5 に答える 5

2

他の投稿者が示唆しているように、アーキテクチャを再考することをお勧めします。自分自身で物事を難しくしているようです。

また、次の点に注意してください。

データ アクセス オブジェクトの依存関係をコンストラクターの依存関係ではなくプロパティに変更することで、Windsor は各オブジェクトを完全にインスタンス化した後にそれらを自動入力します。

気をつけて。これを行う際に、基本的に、これらの依存関係はオプションであることを Windsor に伝えました (コンストラクターを介して注入された依存関係とは異なります)。これらの依存関係が本当にオプションでない限り、これは悪い考えのように思えます。Windsor が必要な依存関係を満たすことができない場合は、それを吐き出します

于 2008-11-14T21:30:44.447 に答える
1

遅延読み込みは、リポジトリではなく、永続化レイヤーで管理する必要があります。

また、 Customer および Product オブジェクトには、リポジトリへの参照が含まれていてはなりません。これは間違っているようです。

于 2008-11-07T19:44:54.857 に答える
1

少なくともキャッスル ウィンザーで機能する、大幅に優れたアプローチを発見しました。データ アクセス オブジェクトの依存関係をコンストラクターの依存関係ではなくプロパティに変更することにより、Windsor は各オブジェクトを完全にインスタンス化した後にそれらを自動入力します。

したがって、以下は問題なく機能します。

public class CustomerDao : ICustomerDao {

    private IProductDao _productDao;

    public IProductDao ProductDao {
        get { return _productDao; }
        set { _productDao = value; }
    }
    public CustomerDao() { }
    public Customer GetById(int id) {
        Customer c = new Customer(_productDao);
        // Query the database and fill out CustomerId
        return c;
    }
}
public class ProductDao : IProductDao {
    private ICustomerDao _customerDao;

    public ProductDao() { }

    public ICustomerDao CustomerDao {
        get { return _customerDao; }
        set { _customerDao = value; }
    }

    public Product[] GetAllForCustomer(Customer customer) {
        return null;
    }

}
于 2008-11-08T01:10:53.170 に答える
0

このような循環依存関係を持つべきではありません。それはただ間違っています。

こぶを乗り越えるために少しの間だけ間違っている必要がある場合は、サービス ロケーターを使用してみてください。これは、コンテナーを認識し、DAO クラスがインスタンス化されているときではなく、コンテナーが使用されたときに依存関係を解決するクラスです。

Rhino.Tools での Oren Eini のサービス ロケーターの実装を確認することをお勧めします (これは IoC と呼ばれる静的クラスです)。

于 2008-11-07T19:45:32.217 に答える
0

私の解決策は、データ アクセス オブジェクトのそれぞれが依存する DAO をコンテナーから直接遅延読み込みすることです。簡単にするために、CustomerDao と ProductDao の両方を BaseDao オブジェクトから継承し、次のように実装します。

public abstract class BaseDao() {
  private ICustomerDao _customerDao;
  protected ICustomerDao _CustomerDao {
    get {
      if(_customerDao == null) _customerDao = IoC.Container.Resolve<ICustomerDao>();
      return _customerDao;
    }
  private IProductDao _productDao;
  protected IProductDao _ProductDao {
    get {
      if(_productDao == null) _productDao = IoC.Container.Resolve< IProductDao  >();
      return _productDao;
    }

}

その後

public class CustomerDao : BaseDao, ICustomerDao {
      public Customer GetById(int id) {
          Customer c = new Customer(_CustomerDao);
          // Query the database and fill out CustomerId
          return c;
      }
 }
public class ProductDao : BaseDao, IProductDao {
      public Product[] GetAllForCustomer(Customer customer) {
          // use the base class's _ProductDao to instantiate Products
      }
 }

私はこれが好きではないので

  • a) 各 DAO がコンテナに依存するようになりました
  • b) 各 Dao が誰に依存しているか、コンストラクターからはわかりません。
  • c) このような基本クラスを使用する場合、各 DAO は少なくとも相互の Dao への暗黙的な依存関係を必要とするか、基本クラスから遅延読み込みを移動することができますが、大量のコードを複製する必要があります。
  • d) 単体テストでは、コンテナーを作成して事前に入力する必要があります
于 2008-11-07T19:46:23.747 に答える