Гранулярность интерфейса - PullRequest
0 голосов
/ 06 июня 2019

на моей работе сегодня я начал бороться со срезом моих интерфейсов.

Чтобы поддерживать некоторые masterdata в моем приложении, я создаю контекст.В этом контексте провайдер данных берет информацию, которая ему нужна, и приводит ее к стратегии для сохранения.

В первой попытке я строю метод в своем контексте для настройки провайдера данных.Например, на основе одного файла и одного из базы данных.

Context->setData(MyProvider->getData() ) ;

Поставщику данных требуются некоторые другие настройки для выполнения работы.Для файла требуется Filepath и поставщик базы данных Modelobject.

Теперь я не уверен, каков наилучший способ определения интерфейса.Создайте общий интерфейс «Провайдер» и позаботьтесь о типе возврата метода getData.Или перейдите с наследованием к созданию специального интерфейса для Fileprovider и для Database.

Interface Fileprovider extends IProvider { void setPath(String Path) ;} 

Или третья возможность - просто создать автономный интерфейс для каждого провайдера.

Спасибо за ваши проблемы

1 Ответ

0 голосов
/ 07 июня 2019

Я бы предложил композицию и базовый IProvider интерфейс (ваш второй подход).Каждый провайдер, вероятно, будет иметь некоторые специальные функции, которые являются индивидуальными и поэтому должны быть инкапсулированы (принцип разделения интерфейса):

Main()
{
  Context context = new Context();

  IFileDataProvider fileDataProvider = new FileDataProvider();

  // Configure the provider
  fileDataProvider->setPath("c:\data");

  context->setProvider(fileDataProvider);

  // Get data. Internally this data is read from the local filesystem
  DataResultObject data = context->getData();

  IDatabaseProvider databaseProvider = new DatabaseProvider();

  // Configure the provider
  databaseProvider->login();

  context->setProvider(databaseProvider);

  // Get data. Internally this data is now read from the database
  DataResultObject data = context->getData();

  // A test case would fake the data provider to reduce complexity and improve performance. 
  // To achieve this a third implementation (a dummy) would be required.
  IProvider fakeDataProvider = new MockDataProvider();
  context->setProvider(fakeDataProvider);

  // Get test data. Internally this data is created by the fake data provider
  DataResultObject data = context->getData();
}

interface IProvider 
{
  DataResultObject getData();
}

interface IFileDataProvider extends IProvider
{
  void setPath(String path);
}

class FileDataProvider implements IFileDataProvider 
{
  void setPath(String path)
  {
    this->path = path;
  }

  DataResultObject getData()
  {
    return readFromFilesystem();
  }
}

interface IDatabaseProvider extends IProvider
{
  void login();
}

class DatabaseProvider implements IDatabaseProvider 
{
  private String credentials = "login credentials";

  void login()
  {
    login(this->credentials);
  }

  DataResultObject getData()
  {
    return readFromDatabase();
  }
}

class MockDataProvider implements IProvider
{
  DataResultObject getData()
  {
    // return empty or dummy data
    return new DataResultObject();
  }
}

class Context
{
  IProvider provider;

  public Context(IProvider provider)
  {
    this.provider = provider;
  }

  public DataResultObject getData()
  {
    return this.provider->getData();
  }

  public void setContext(IProvider provider) 
  {
    this.provider = provider;
  }
}

Если экземпляр IProvider изменится на том же объекте Context, то я быдобавить сеттер для переключения экземпляров.В противном случае конструктор является лучшим выбором.

Использование выделенного интерфейса для каждого типа провайдера исключает возможность переключения между провайдерами, поскольку устраняет полиморфизм.Переключение может быть полезно при написании модульных тестов.Затем вы можете легко смоделировать базу данных или файловую систему.

И использование одного общего интерфейса заставит, например, DatabaseProvider реализовать избыточные FileDataProvider специфические методы.Это может быть очень раздражающим и запутанным, когда классы содержат фиктивные реализации.Принцип сегрегации интерфейса ('i' в SOLID ) рекомендует по ряду веских причин избегать такого рода дизайна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...