Jak ustrukturyzować interfejsy, gdy obiekty wykorzystują tylko część interfejsu?

9

Mam projekt, w którym mam dwie klasy, które obie wymagają obiektu dostępu do bazy danych, który aktualizuje tę samą tabelę. Ograniczenia frameworka i projektu sprawiają, że nie mogę łączyć tych dwóch klas. Utworzyłem poniżej skrzynkę, która pokazuje, jak wygląda konfiguracja. Klasa A musi mieć możliwość aktualizacji i odczytu rekordu, podczas gdy klasa B musi mieć możliwość aktualizacji i usunięcia rekordu.

Jeśli używam klas takimi, jakimi są, działa dobrze, ale mam problem z tym, że każda z klas wymaga funkcjonalności, której nie używa do wdrożenia. Na przykład, aby użyć klasy A, muszę przekazać temu dao, który implementuje funkcję usuwania, nawet jeśli nigdy nie zostanie wywołana. Podobnie, muszę przekazać klasie B dao, który implementuje funkcję odczytu, ale nigdy nie zostanie wywołany.

Pomyślałem o podejściu do niego przez interfejsy, które dziedziczą inne (IReaddę, IUpdate-da, IDeleteexe to daos, które zostaną odziedziczone), ale to podejście wymagałoby zasadniczo innego interfejsu dla każdej kombinacji funkcji (IUpdateAndRead, IReadAndDelete, IReadAndUpdate ... )

Chcę użyć interfejsu dla dao, ponieważ nie chcę łączyć aplikacji z bazą danych. Czy istnieje wzór lub metoda realizacji tego, czego chcę, o czym ktoś wie? Z góry dziękuję.

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
źródło
2
Dlaczego potrzebujesz osobnych interfejsów dla każdej kombinacji, a nie tylko, aby każda klasa, która ich używa, implementowała te, których potrzebują?
yitzih
W powyższym przypadku zamiast przekazać IDao konstruktorowi A, musiałbym przekazać obiekt, który implementuje IUpdate i IRead, więc jaki byłby typ zmiennej instancji „dao”? Czy nie musiałoby to być coś takiego jak IUpdateAndRead,7? Nadal musi to być interfejs, ponieważ jeśli powiem mu, aby wziął implementację specyficzną dla bazy danych, połączyłem klasę z db. Czy o to pytałeś?
jteezy14
3
Myślę, że jest to doskonały przykład zasady segregacji interfejsu ( Iod SOLID). Może chciałbym trochę o tym przeczytać.
Christopher Francisco

Odpowiedzi:

10

Według komentarza Christophera prawdopodobnie lepiej jest segregować interfejsy . Więc trzeba co najmniej IReadDao, IDeleteDaoi IUpdateDao. Zauważ, że niekoniecznie potrzebujesz trzech klas; możesz mieć jedną dużą klasę DAO, która implementuje wszystkie trzy interfejsy, jeśli ma to sens, aby baza kodu była w ten sposób łączona.

Aby uniknąć kombinatorycznej eksplozji (tak aby uniknąć potrzebę stosowania IReadUpdate, IDeleteUpdateitp powłoka) można dostarczyć osobno interfejsy wtrysku konstruktor (można przekazać ten sam obiekt dwukrotnie innych parametrów), lub stanowić jeden obiekt danych obsługującego dwie lub więcej interfejsów w ogólnym wywołaniu metody za pomocą extends.

Wtrysk konstruktora:

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

Iniekcja setera za pomocą metody ogólnej:

<T extends IUpdateDao & IDeleteDao> void InitializeDao(T dao)  //Pass a single object that implements both IUpdateDao and IDeleteDao
John Wu
źródło
Kiedy korzystam z zastrzyku settera, jak mam zadeklarować zmienną instancji, którą ustawiam w funkcji Initializedo?
jteezy14
Potrzebne będą dwie zmienne instancji (jedna do usuwania, jedna do aktualizacji) ... przypisz daodo obu.
John Wu
O tak, to ma sens. Dziękuję bardzo za świetną odpowiedź!
jteezy14