Основанное на интерфейсе программирование в C++ в сочетании с итераторами. Как также сохраняют это простым?

В моих разработках я медленно перемещаюсь от объектно-ориентированного подхода до подхода интерфейсного основанного программирования. Более точно:

  • в прошлом я был уже удовлетворен, мог ли я сгруппировать логику в классе
  • теперь я склонен помещать больше логики позади интерфейса и позволять фабрике создать реализацию

Простой пример разъясняет это.

В прошлом я записал эти классы:

  • Библиотека
  • Книга

Теперь я пишу эти классы:

  • ILibrary
  • Библиотека
  • LibraryFactory
  • IBook
  • Книга
  • BookFactory

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

Для большинства случаев это работает очень хорошее, но это становится проблемой, если я хочу использовать итераторы для цикличного выполнения по наборам.

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

for (Library::iterator it=myLibrary.begin();it!=mylibrary.end();++it) ...

Проблема состоит в том, что в основанном на интерфейсе подходе, нет никакой гарантии, что различные реализации ILibrary используют тот же вид итератора. Если, например, OldLibrary и NewLibrary оба наследовались ILibrary, то:

  • OldLibrary мог использовать станд.:: вектор для хранения его книг и станд. возврата:: вектор:: const_iterator в начинаться и методы конца
  • NewLibrary мог использовать станд.:: перечислите для хранения его книг и станд. возврата:: список:: const_iterator в начинаться и методы конца

При требовании обоих, реализации ILibrary для возврата того же вида итератора не являются решением также, с тех пор на практике, инкрементная операция (++ это) должна быть реализована по-другому в обеих реализациях.

Это означает, что на практике я должен сделать итератор интерфейсом также, подразумевая, что приложение не может поместить итератор на стек (типичная проблема разрезания C++).

Я мог решить эту проблему путем обертывания интерфейса итератора в неинтерфейсном классе, но это кажется довольно сложным решением для того, что я пробую к obtian.

Там лучшие пути состоят в том, чтобы решить эту проблему?

Править: Некоторые разъяснения после комментариев сделаны Martin.

Предположим, что у меня есть класс, который возвращает все книги, отсортированные на популярности: LibraryBookFinder. Это имеет, начинаются () и конец () методы, которые возвращают LibraryBookFinder:: const_iterator, который обращается к книге.

Для замены моей старой реализации совершенно новой я хочу поместить старый LibraryBookFinder позади интерфейса ILibraryBookFinder и переименовать старую реализацию к OldSlowLibraryBookFinder.

Затем мое новое (образование пузырьков быстро) реализация под названием VeryFastCachingLibraryBookFinder может наследоваться ILibraryBookFinder. Это - то, куда проблема итератора возникает из.

Следующий шаг мог быть должен скрыть интерфейс позади фабрики, где я могу попросить, чтобы фабрика "дала мне 'средство поиска', которое очень хорошо в возврате книг согласно популярности, или согласно заголовку или автору.... Вы заканчиваете с кодом как это:

ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_POPULARITY);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...

или если я хочу использовать другого критерии:

ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_AUTHOR);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...

Аргумент LibraryBookFinderFactory может быть определен внешним фактором: параметр конфигурации, параметр командной строки, выбор в диалоговом окне... И каждая реализация имеет свой собственный вид оптимизации (например, автор книги не изменяется так, это может быть довольно статическим кэшем; популярность может ежедневно изменяться, который может подразумевать полностью другую структуру данных).

9
задан Patrick 19 October 2010 в 02:47
поделиться