Bagaimana cara membuat antarmuka saat objek hanya menggunakan sebagian dari antarmuka?

9

Saya punya proyek di mana saya memiliki dua kelas yang keduanya memerlukan objek akses database yang memperbarui tabel yang sama. Batasan-batasan dari kerangka kerja dan proyek membuatnya sehingga saya tidak dapat menggabungkan kedua kelas ini. Saya telah membuat case di bawah ini yang menunjukkan bagaimana pengaturannya. Kelas A harus dapat memperbarui dan membaca catatan, sedangkan kelas B harus dapat memperbarui dan menghapus catatan.

Jika saya menggunakan kelas sebagaimana adanya, itu berfungsi dengan baik, tetapi saya mengalami masalah dengan fakta bahwa masing-masing kelas membutuhkan fungsionalitas yang tidak digunakan untuk diimplementasikan. Misalnya, untuk menggunakan kelas A, saya harus memberikannya dao yang mengimplementasikan fungsi delete, meskipun tidak akan pernah dipanggil. Demikian pula, saya harus lulus kelas B a dao yang mengimplementasikan fungsi baca tetapi tidak akan pernah dipanggil.

Saya berpikir untuk mendekatinya dengan memiliki antarmuka yang mewarisi yang lain (IReadDao, IUpdatePOR, IDeletePOR menjadi daos yang akan diwarisi dari), tetapi pendekatan ini pada dasarnya akan memerlukan antarmuka yang berbeda untuk setiap kombinasi fungsi (IUpdateAndRead, IReadAndDelete, IReadAndUpdate ... )

Saya ingin menggunakan antarmuka untuk dao karena saya tidak ingin memasangkan aplikasi dengan database. Apakah ada pola atau metode untuk mencapai apa yang saya inginkan yang diketahui orang lain? Terima kasih sebelumnya.

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);

  }

}
jteezy14
sumber
2
Mengapa Anda memerlukan antarmuka terpisah untuk setiap kombinasi dan bukannya hanya memiliki setiap kelas yang menggunakannya mengimplementasikan yang mereka butuhkan?
yitzih
Dalam kasus di atas, daripada meneruskan IDao ke konstruktor A, saya harus meneruskan objek yang mengimplementasikan IUpdate dan IRead, jadi seperti apa variabel variabel "dao" itu? Bukankah itu harus seperti IUpdateAndReadDao? Itu masih perlu sebuah antarmuka karena jika saya mengatakannya untuk mengambil implementasi yang spesifik database saya telah menggabungkan kelas ke db. Itukah yang kamu tanyakan?
jteezy14
3
Saya pikir ini adalah contoh sempurna dari Prinsip Segregasi Antarmuka (yang Idari SOLID). Mungkin ingin membaca sedikit tentang itu.
Christopher Francisco

Jawaban:

10

Per komentar Christopher, mungkin sedikit lebih baik untuk memisahkan antarmuka . Jadi, Anda akan membutuhkan setidaknya IReadDao, IDeleteDao, dan IUpdateDao. Perhatikan bahwa Anda tidak perlu tiga kelas; Anda dapat memiliki satu kelas DAO besar yang mengimplementasikan ketiga antarmuka, jika masuk akal jika basis kode digabungkan dengan cara itu.

Untuk menghindari ledakan kombinatorial (misalnya untuk menghindari kebutuhan untuk IReadUpdate, IDeleteUpdate, dll antarmuka) Anda dapat memberikan interface secara terpisah di injeksi konstruktor (Anda dapat melewati objek yang sama dua kali parameter yang berbeda), atau memberikan satu objek yang mendukung dua atau lebih interface dalam panggilan metode generik menggunakan extends.

Injeksi konstruktor:

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....
}

Setter injeksi, menggunakan metode generik:

<T extends IUpdateDao & IDeleteDao> void InitializeDao(T dao)  //Pass a single object that implements both IUpdateDao and IDeleteDao
John Wu
sumber
Saat menggunakan injeksi setter, bagaimana saya mendeklarasikan variabel instan yang saya atur dalam fungsi InitializeDao?
jteezy14
Anda akan membutuhkan dua variabel instan (satu untuk menghapus, satu untuk pembaruan) ... menetapkan daokeduanya.
John Wu
Oh ya, itu masuk akal. Terima kasih banyak atas jawabannya!
jteezy14