Як я структурую інтерфейси, коли об’єкти використовують лише частину інтерфейсу?


9

У мене є проект, в якому я маю два класи, які вимагають об'єкта доступу до бази даних, який оновлює ту саму таблицю. Обмеження рамки та проекту роблять це таким, що я не можу поєднати ці два класи. Нижче я створив випадок, який показує, як відбувається налаштування. Клас A повинен мати можливість оновлювати та читати запис, тоді як клас B повинен мати можливість оновити та видалити запис.

Якщо я використовую класи такими, якими вони є, це працює просто чудово, але у мене виникає проблема з тим фактом, що для кожного з класів потрібна функціональність, яку він не використовує. Наприклад, для використання класу A я повинен передати йому дао, який реалізує функцію видалення, навіть якщо вона ніколи не буде викликана. Так само я повинен пройти клас B дао, який реалізує функцію читання, але вона ніколи не буде викликана.

Я думав про наближення до нього, маючи інтерфейси, які успадковують інших (IReadDao, IUpdateDao, IDeleteDao - це даоси, які отримали б у спадок від), але цей підхід в основному вимагає іншого інтерфейсу для кожної комбінації функцій (IUpdateAndRead, IReadAndDelete, IReadAndUpdate ... )

Я хочу використовувати інтерфейс для дао, оскільки я не хочу поєднувати додаток із базою даних. Чи існує закономірність чи метод досягнення того, що я хочу, щоб хтось знав про це? Заздалегідь спасибі.

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
Навіщо потрібні окремі інтерфейси для кожної комбінації, а не просто кожен клас, який використовує їх, реалізувати ті, які їм потрібні?
йіці

У вищенаведеному випадку, а не передавати IDao конструктору A, я повинен був би передати об’єкт, який реалізує IUpdate та IRead, то яким буде тип змінної екземпляра "dao"? Хіба це не повинно бути чимось на зразок IUpdateAndReadDao? Це все ще повинен бути інтерфейсом, тому що якщо я скажу йому взяти реалізацію, що відповідає специфічній базі даних, я з'єднав клас з db. Це те, про що ви питали?
jteezy14

3
Я думаю, що це ідеальний приклад принципу сегрегації інтерфейсів ( Iвід SOLID). Можливо, хочете трохи прочитати на ньому.
Крістофер Франциско

Відповіді:


10

За коментарем Крістофера, можливо, трохи краще розділити інтерфейси . Так що вам потрібно, по крайней мере IReadDao, IDeleteDaoі IUpdateDao. Зауважте, що вам не обов’язково потрібні три класи; у вас може бути один великий клас DAO, який реалізує всі три інтерфейси, якщо має сенс поєднувати базу коду таким чином.

Для того, щоб уникнути комбінаторних вибуху (наприклад , щоб уникнути необхідності застосування IReadUpdate, IDeleteUpdateі т.д. інтерфейсу) ви можете надати інтерфейси окремо в ін'єкції конструктора (ви можете пройти один і той же об'єкт в два раз різних параметрів), або надати один об'єкт , що підтримують два або більше інтерфейсів в загальному методі виклику з використанням 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

Вам знадобиться дві змінні екземпляра (одна для видалення, друга для оновлень) ... призначити daoобом.
Джон Ву

О так, це має сенс. Дуже дякую за чудову відповідь!
jteezy14
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.