Повторное использование интерфейсов в вашем приложении - PullRequest
0 голосов
/ 24 сентября 2010

В настоящее время я занят рефакторингом больших частей в моем приложении.Основная цель - удалить как можно больше зависимостей между различными модулями.Теперь я натыкаюсь на следующую проблему:

В моем приложении у меня есть модуль GUI, который определил интерфейс IDataProvider.Интерфейс должен быть реализован приложением и используется для «предоставления данных» модулю GUI.Например, сетке данных можно присвоить этот IDataProvider и использовать его для циклического перебора всех экземпляров, которые должны быть показаны в сетке данных, и получения их данных.

Теперь есть еще один модуль (на самом деле довольно много модулей)что всем нужно что-то подобное (например, модуль отчетности, модуль интеграции с базой данных, модуль математического решения, ...).В этот момент я вижу две вещи, которые я могу сделать:

  • Я мог бы переместить IDataProvider со слоя GUI на намного более низкоуровневый уровень и повторно использовать этот же интерфейс во всех других модулях.
    • Преимущество этого заключается в том, что приложению становится проще использовать все модули (ему нужно только реализовать поставщика данных).
    • Недостатком является то, что я ввожу зависимость междумодули и центральный IDataProvider.Если кто-то начинает расширять IDataProvider дополнительными методами, необходимыми для одного модуля, он также начинает загрязнять другие модули.
  • Другой альтернативой является предоставление каждому модулю своего собственного поставщика данных, и принудительноприложение, чтобы реализовать их все, если оно хочет использовать все модули.
    • Преимущество состоит в том, что модули не зависят от общей части
    • Недостатком является то, что я получаю IGridDataProvider, IReportDataProvider, IDatabaseDataProvider, ISolverDataProvider.

Какой наилучший подход использовать?Приемлемо ли сделать все модули зависимыми от одного и того же общего интерфейса, если им требуется [почти или полностью] один и тот же интерфейс?

Если я использую один и тот же интерфейс IDataProvider, может ли это привести к неприятным проблемам в будущем (о котором я не знаю в данный момент)?

Ответы [ 4 ]

1 голос
/ 24 сентября 2010

Почему бы вам не сделать промежуточную реализацию? Пусть некоторые классы реализуют повторяющиеся части IDataProvider (как в первом случае) в разложенной библиотеке (или другом слое). Также каждый должен «реализовать» свои IDataProvider (как во 2-м случае). Затем вы можете повторно использовать вашу реализацию IDataProvider повсеместно и добавлять определенные методы в пользовательские классы, создав производный класс ...

т.е:.

    // Common module.
class BasicDataProvider : IDataProvider
{
public:
    // common overrides...
};

    // For modules requiring no specific methods...
typedef BasicDataProvider ReportDataProvider;

    // Database module requires "special" handling.
class DatabaseDataProvider : BasicDataProvider
{
public:
    // custom overrides...
};
1 голос
/ 24 сентября 2010

Существует альтернатива недостатку, который вы приводите для перемещения IDataProvider на более низкий уровень.

Модуль, которому требуется расширенный интерфейс, может поместить эти расширения в свой собственный подчиненный интерфейс IDataProvider.Вы можете поощрять это, активно создавая эти подчиненные интерфейсы.

1 голос
/ 24 сентября 2010

Я не против иметь несколько модулей в зависимости от одного интерфейса, даже если он не использует все методы, которые публикует интерфейс.Вы также можете больше думать о части интерфейса, а не о том, для какого модуля он предназначен.Большинству упомянутых вами модулей нужен только доступ для чтения.Таким образом, вы могли бы разделить таким образом и иметь другой для записи и т. Д.

Слой данных не должен знать, для чего используются данные (что является работой уровня представления).Нужно только знать, как его вернуть и как его изменить.

Более того, нет абсолютно никаких проблем с переводом поставщика данных (который также может быть помечен как контроллер) на более низкий уровень, поскольку он, вероятно, ужереализация некоторой бизнес-логики (например, согласованность данных), которая не имеет ничего общего с пользовательским интерфейсом.

1 голос
/ 24 сентября 2010

Если вы беспокоитесь, что к интерфейсу будут применены дополнительные методы, вы можете использовать шаблон адаптера.То есть:

class myFoo{
public:
    Bar getBar() =0;
}

и в другом модуле:

class myBaz{
public:
    Bar getBar() =0;
}

Затем использовать одно с другим:

class MyAdaptor: public myBaz{
public:
    MyAdaptor(myFoo *_input){
        m_Foo = _input;
    }

    Bar getBar(){ return m_Foo->getBar(); }

private:
    myFoo* m_Foo;
}

Таким образом, вы реализуете все вВаш myBaz интерфейс и нужно только поставить клей в одном месте.В myFoo может быть добавлено столько дополнительных методов, сколько нужно, остальная часть вашего приложения не должна знать об этом или заботиться о нем.

...