オブジェクトがインターフェイスの一部のみを使用する場合、インターフェイスをどのように構成しますか?


9

同じテーブルを更新するデータベースアクセスオブジェクトを必要とする2つのクラスがあるプロジェクトがあります。フレームワークとプロジェクトの制約により、これら2つのクラスを組み合わせることはできません。以下のケースを作成して、セットアップ方法を示します。クラスAはレコードを更新および読み取りできる必要があり、クラスBはレコードを更新および削除できる必要があります。

クラスをそのまま使用すると問題なく機能しますが、各クラスが実装に使用していない機能を必要とするという問題があります。たとえば、クラスAを使用するには、削除関数が呼び出されない場合でも、削除関数を実装するdaoを渡す必要があります。同様に、クラスBにread関数を実装するdaoを渡す必要がありますが、呼び出されることはありません。

他を継承するインターフェイス(IReadDao、IUpdateDao、IDeleteDaoは継承元のdaos)を使用してアプローチすることを考えましたが、このアプローチでは基本的に、関数の組み合わせごとに異なるインターフェイス(IUpdateAndRead、IReadAndDelete、IReadAndUpdate ... )

アプリケーションとデータベースを結合したくないので、daoのインターフェースを使用します。誰かが知っている私がやりたいことを達成するためのパターンや方法はありますか?前もって感謝します。

class IDao {

  void update(ModelDao model);
  void delete(String guid);
  ModelDao read(String guid);

}

Class A {

  private IDao dao;

  public A(IDao dao) {

    this.dao = dao;

  }

  public void doStuff() {

    ModelDao model = new ModelDao();

    ...

    dao.update(model);

  }

  public void readThenDoSomething(String id) {

    ModelDao model = dao.read(id);

    ...

  }

}

Class B {

  private IDao dao;

  public B(IDao dao) {

    this.dao = dao;

  }

  public void makeUpdate() {

    ModelDao model = new ModelDao();

    ...

    dao.update(model);

  }

  public void delete(String id) {

    dao.delete(id);

  }

}

2
それらを使用する各クラスに必要なものを実装させるのではなく、組み合わせごとに個別のインターフェースが必要なのはなぜですか?
yitzih 2017

上記の場合、IDaoをAのコンストラクターに渡すのではなく、IUpdateとIReadを実装するオブジェクトを渡さなければならないので、インスタンス変数「dao」の型はどうなるでしょうか。IUpdateAndReadDaoのようにする必要はありませんか?データベース固有の実装を取るように指示すると、クラスがデータベースに結合されたので、それはまだインターフェースである必要があります。それはあなたが求めていたものですか?
jteezy14

3
これはインターフェース分離の原則(Ifrom SOLID)の完璧な例だと思います。少し読みたくなるかもしれません。
クリストファーフランシスコ

回答:


10

クリストファーのコメントによると、インターフェース分離する方がおそらく少し良いです。あなたは少なくとも必要がありますのでIReadDaoIDeleteDao、とIUpdateDao。3つのクラスは必ずしも必要ではないことに注意してください。そのようにコードベースを組み合わせることが理にかなっている場合は、3つのインターフェイスすべてを実装する1つの大きなDAOクラスを持つことができます。

組み合わせ爆発を避けるために(例えばの必要性を回避するためにIReadUpdateIDeleteUpdateなどのインタフェース)あなたは、別途インターフェースコンストラクタ・インジェクションで提供することができます(あなたが二度異なるパラメータと同じオブジェクトを渡すことができます)、または二つ以上のインターフェイスをサポートする単一のオブジェクトを提供しますを使用したジェネリックメソッド呼び出しextends

コンストラクター注入:

class MyDaoLibrary : IUpdateDao, IInsertDao, IDeleteDao {
    //Etc....
}

class A
{
    //It is OK if the IoC container factory provides the same instance for both parameters.
    a(IUpdateDao dao1, IDeleteDao dao2) {
        this.updater = dao1;
        this.deleter = dao2;
    }
    //Etc....
}

一般的な方法を使用したセッター注入:

<T extends IUpdateDao & IDeleteDao> void InitializeDao(T dao)  //Pass a single object that implements both IUpdateDao and IDeleteDao

セッターインジェクションを使用する場合、InitializeDao関数で設定するインスタンス変数をどのように宣言しますか?
jteezy14 2017

2つのインスタンス変数が必要です(1つは削除用、もう1つは更新用)... dao両方に割り当てます。
ジョン・ウー

ああ、そうですね。すばらしい答えをありがとう!
jteezy14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.