web-dev-qa-db-ja.com

オブジェクトのコンストラクターでDAO呼び出しを行うことは悪い習慣と考えられていますか?

DAOを介したデータレイヤーへの2つの個別の呼び出しを必要とするオブジェクトをインスタンス化するための最良の設計を理解しようとしています。オブジェクトは、これらの呼び出しが行われるまで使用できません(データベースからデータを取得する必要があるため)。私は3つの可能な解決策を考え出しました:

  1. データベースから必要なデータを取得するメソッドをDAO自体に作成し、そのデータをオブジェクトのコンストラクターに渡します。オブジェクトは戻り値として返されます。
  2. オブジェクトを使用しているクラスにメソッドを作成します。このメソッドは、DAOで両方のパブリックメソッドを呼び出し、次にステップ1のようにインスタンス化してオブジェクトを返します。
  3. DAOをパラメーターとしてオブジェクトのコンストラクターに渡します。次に、コンストラクターはDAOに必要な両方の呼び出しを行い、セッターを必要とせずに独自のメンバー変数を設定します。 DAOはコンストラクター以外では使用されません。

たとえば、SomeObjectが作成したいオブジェクトで、Fooがそれを利用するクラスであるとします。

1-DAOには次のロジックが含まれます。

public SomeObject getSomeObject(){ // this DAO method called by Foo class
     data1 = getData1();
     data2 = getData2();
     return new SomeObject(data1,data2);
}

2-オブジェクトを使用するクラスにはロジックが含まれています。

public class Foo {
    ...
         public void useSomeObject() {
              SomeObject obj = createSomeObject();
              obj.doStuff();
         }

         private SomeObject createSomeObject() {
              data1 = dao.getData1();
              data2 = dao.getData2();
              SomeObject someObject = new SomeObject(data1,data2);
              return someObject;
         } 
}

3-SomeObjectはDAOをパラメーターとして受け取り、コンストラクターで使用します。

public class SomeObject {
...
      public SomeObject(DAO dao) {
           data1 = dao.getData1();
           data2 = dao.getData2();
      }
...
 }

うまくいけば、これらの例は私のポイントを伝えるのに十分です。これらのソリューションのいずれかが他よりも優れた設計と見なされていますか?そうでない場合、どのソリューションがベストプラクティスと見なされますか?

ありがとう。

6
Wallace Brown

従来のOOPでは、カプセル化の概念は、データとコードを組み合わせるという考え方を具体化しています。つまり、それらが表すデータに特に作用するメソッドを提供します。したがって、たとえば、Customerオブジェクトには、特に顧客の「動作」に関係するメソッドのみが含まれます。

オブジェクトの永続化は、直交する問題です。

Customerオブジェクトは、データベース、XMLファイルなどからどのように保存または取得されるかについては何も知ってはなりません(概念はPersistence Ignoranceと呼ばれます)。 。このため、特に大規模なシステムでは、オブジェクトリレーショナルマッパーなどの一般化された永続化メカニズムを使用してオブジェクトを格納および取得し、次にオブジェクトを返すか、またはビジネスアクションを実行するリポジトリメソッドを介してその機能を引き出します。データ。

これにより、作成するクラスごとに永続化実装をコーディングする必要がなくなります。

さらに読む
作業単位のパターンと永続性の無視

4
Robert Harvey

例1のアプローチでは、DAOにコンストラクターを呼び出し、リポジトリパターンに非常に近づけます。

ただし、実際のリポジトリで調整を行う方が理にかなっています。

class SomeObjectRepository {
  SomeObjectDAO sod;
  ...
  SomeObject getSomeObject() {
    return new SomeObject(sod.getData1(), sod.getData2());
  }
}

DAOは、作成時にリポジトリ(シングルトン)にバインドされます。次に、Fooはリポジトリメソッドを呼び出してオブジェクトを取得します。

このようにして、オブジェクトはDAOから分離され、DAOは基本的な操作のみを実行し、互いに対してより簡単にテストされます。

3
BobDalgleish

私はあなたの3番目のオプションで行きます。それはあなたがあなたが望むどんなDAOを渡すことを可能にし、そしてそれはテストのために非常に有用であるかもしれません。また、コードが少し柔軟になります。データ取得の詳細が変更された場合、DAOクラスを変更するだけで、SomeObjectはほぼ同じように機能します。

最初のオプションはそれほど悪くありません。データ取得メソッドはSomeObject内にあるため、クラスはビジネスオブジェクトとDAOになります。

2番目のオプションは、createSomeObjectを作成する必要性が増加し、アプリケーション全体に広がるため、SomeObjectがコピーされて貼り付けられる状況につながる可能性があります(わかっているかもしれませんが、そうではないかもしれませんが、かもしれません)。そして、それが起こったら、SomeObjectのコンストラクターなど、データ取得コードを中心的な場所に置いて、そこから始めたいと思うでしょう。