2014-01-18 3 views
0

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

Я смотрел Robert C Martin(Uncle Bob) -Clean Architecture and Design-2012 COHAA The Path to Agility Conference. Во время разговора он рассказывает историю о развитии Fitnesse. Я не знаком с программным обеспечением, поэтому я ищу его и найду the project hosted on github.

При просмотре проекта, одна вещь привлекает мое внимание в WikiPage interface: метод PageCrawler getPageCrawler();. Поэтому я просматриваю PageCrawler interface, чтобы посмотреть, как это выглядит. Изучив этот интерфейс, я думаю, что методы в PageCrawler выглядят так, как будто они будут принадлежать WikiPage и что WikiPage может разумно реализовать интерфейс.

Я бы подумал, что разделение двух может привести к тому, что WikiPage будет подвергать внутренности, чтобы информация, необходимая для сканирования страницы, была доступна для объектов, которые сканируют ее. Кроме того, абстрактный класс BaseWikiPage просто возвращает новый PageCrawlerImpl, и нет никаких других PageCrawler реализаций в проекте из того, что я вижу.

Я видел этот тип кода в других проектах, где метод одного интерфейса/класса возвращает объект другого интерфейса/класса с методами, которые могут разумно принадлежать первому классу. Пытаясь увидеть намерение разработчиков Fitnesse, единственной причиной такого дизайна, с которой я столкнулся, является то, что разработчикам, которые создают новые вики-страницы путем реализации WikiPage, не требуется повторная реализация функций обхода, то есть функциональность обхода должны быть одинаковыми независимо от реализации страницы wiki. Является ли это целью такого дизайна, или я что-то упускаю?

Я нашел вопрос Implementing an interface vs. providing an interface на SO, но это было не совсем то же самое и не давало большого понимания, когда вы можете создать что-то подобное.

ответ

2

То, что вы видите, является Принципом разделения сегментов в действии. Вы говорите, что интерфейс PageCrawler заставляет вас думать, что «это все, что принадлежит WikiPage», но это смотрит на вещи с точки зрения реализации, а не на точку зрения кого-то, вызывающего WikiPage.

EDIT: Возможно, речь идет о принципе разделения сегментов и о принципе единой ответственности.

+0

Спасибо, Джон, я так не думал об этом. Однако моя интерпретация ISP отличается. Я думал, что интернет-провайдер разделяет обязанности на единые интерфейсы и создает объект, реализуя интерфейсы, не обязательно возвращая объект из метода, реализующего интерфейс. В этом случае я думаю, что существование интерфейса 'PageCrawler' - это использование ISP. Если «WikiPage» реализует его, клиенты интерфейса «PageCrawler» до сих пор не знают, что разработчик является «WikiPage». – TheSecretSquad

+0

Кроме того, похоже, что вы говорите, что клиенты 'WikiPage' не должны знать о методах' PageCrawler' (это то, что вы имели в виду?), Но у них все еще есть доступ к ним, но теперь они зависят от того, что кажется избыточное сообщение ('getPageCrawler'). Разве это не лучше, если использовать декоратор, например, если WikiPage реализует 'PageCrawler', а затем' WikiPage' может выбрать делегирование отдельному объекту внутри, который также реализует 'PageCrawler'? Я предполагаю, что моя перспектива: они говорят, что «WikiPage» имеет «PageCrawler», но для меня «WikiPage» является _crawlable_. – TheSecretSquad

1

В некоторых случаях некоторые функции, «связанные» с объектом, должны содержать состояние, которое должно быть отделено от самого объекта. В .NET методы IEnumerator<T> являются яркими примерами этого. Их значение обычно происходит из ассоциированного IEnumerable<T>, но каждый перечислитель имеет состояние, которое должно быть отделено от состояния базовой коллекции (особенно, поскольку типичная реализация IEnumerable<T> не имеет способа узнать, сколько счетчиков, каждое из которых имеет независимое состояние, может быть связаны с ним одновременно

несколько больше преимуществ отщепления реализаций интерфейса:.

  • отщепленной реализация может включать в себя пользователь, чьи имена отражают те из базового типа, но функциональность которых отличаются.Например, реализует IEnumerable<KeyValuePair<TKey,TValue>>, но имеет свойство Keys, которое реализует IEnumerable<TKey>. И Dictionary, и вещь, возвращаемая Keys, имеют метод GetEnumerator, но один перечисляет пары ключ-значение, а другой просто перечисляет ключи.

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

  • Хотя ни Java, ни .NET не допускают двойное наследование, может быть возможным для каждого из тесно связанных объектов наследовать от другого класса.

Я не знаком с конкретными типами вы упоминаете, так что я не знаю конкретных причин, они ведут себя, как они делают, но причины назвать все распространенные из них.

Смежные вопросы