ООП: В каких ситуациях дизайн на основе классов лучше, чем дизайн на основе интерфейса?

9

Я читал сайт JDOM .

Почему JDOM API определяется в терминах конкретных классов, а не интерфейсов?

Джейсон Хантер суммирует аргументы против интерфейсного API для JDOM:

С интерфейсами все становится фабрикой, элементы должны «импортироваться» в новые документы, а не просто добавляться, такие функции, как долгосрочная сериализация, не могут быть гарантированы, и этот список можно продолжить.

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

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

Возможно, использование конкретных классов целесообразно в определенных местах. Существуют ли общие проблемы классов, для которых использование конкретных классов в дизайне нормально?

Винот Кумар СМ
источник
Вы можете взглянуть на это: javaworld.com/javaworld/jw-09-2001/jw-0921-interface.html
NoChance
Вы также можете ознакомиться с серией «Ограничьте свои абстракции»: ayende.com/blog/153889/…
henginy
«Мы сделали, и дизайн был намного лучше для него». - как было лучше?
CodeART

Ответы:

5
  • Наследование создает зависимости от реализации , что может быть большой проблемой в отношении сопровождения. Следствием этого является то, что вы можете безопасно использовать наследование и конкретные классы при работе с объектом передачи данных , который по определению почти не содержит реализации. Вы также можете использовать наследование конкретных классов, когда вы хотите эту зависимость. Возможно, вы захотите использовать абстрактный класс, содержащий общие методы (обычно служебные функции) в верхней части иерархии в этой ситуации.
  • При использовании конкретной иерархии классов не забывайте применять принцип подстановки Лискова .
  • Нет проблем с использованием конкретных классов для клиентов (то есть классов, которые используют, а не классов, которые используются).
  • ИМХО, вы можете использовать конкретные классы, пока есть что изменить. Принцип Open / Closed сказал бы вам использовать интерфейсы, чтобы избежать связывания, но в отношении принципа « Вы не нуждаетесь в этом» вы можете рассмотреть возможность использования конкретных классов до того момента, когда вам нужно что-то изменить в реализации. Проблема в том, что вам придется менять каждого клиента ваших классов, когда что-то где-то меняется. Хотя у вас есть только один возможный инструмент, чтобы сделать что-то, вы можете использовать конкретные классы IMO.

[EDIT] Сайт JDOM берет в качестве примера java.io.File, но это определенно интерфейс, основанный на интерфейсе, поскольку можно манипулировать экземпляром java.io.File, как если бы он был только Serializable. В этой ситуации только «создатели» будут знать конкретный класс

Матиас Жуан
источник
Есть два противоречивых определения «объекта стоимости», плавающего вокруг. Ваш, кажется, менее распространенный, также известный как «объект передачи данных».
Майкл Боргвардт
@MichaelBorgwardt Спасибо за то, что указал на это, поскольку я имел в виду не только «объект передачи данных»: я редактирую свой ответ
Матиас Жуан
1
LSP важен для любых отношений подтипов, реализации интерфейса, а также наследования.
2

С сайта JDOM:

Джейсон (Хантер) основал проект JDOM в начале 2000 года вместе с Бреттом Маклафлином

То есть примерно во время появления Java 1.3. Когда дело дошло до разработки Java, не было ничего зрелого - самые опытные разработчики в лучшем случае использовали только 4 года. Не было ни широко используемых контейнеров IoC, ни Hibernate. Apache Struts только начинал.

Все это говорит о том, что Джейсон и Бретт были просто неправы. Многие люди еще не «поняли». Если у них были фоны C ++, ну, вам не нужны интерфейсы в C ++ (ну, они были в C ++, но они вам действительно не нужны, верно?), Зачем, черт возьми, использовать их в Java? Ну, есть много веских причин, на которые другие могут указать вам.

Они определенно ошибались

все, что может быть сделано с интерфейсами, может быть сделано с помощью подклассов

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

Мэтью Флинн
источник
2

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

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

Чтобы сделать вещи более сложными, есть несколько вариантов использования интерфейсов, просто чтобы упомянуть:

  • один заключается в разработке «контракта» или «спецификации» без «реализации»
  • другой, чтобы добавить функцию к существующему классу или иерархии классов
  • дополняет предыдущий, чтобы предоставить общий доступ к различным объектам, технологиям, например: Enterprise Beans, CORBA, COM, WebServices
  • подражать множественному наследованию

Ваш вопрос относится к первому пункту.

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

И оставьте интерфейсы для других сценариев.

Хорошим примером являются библиотеки виджетов (элементов управления).

Я предлагаю взглянуть на другие языки программирования, как они используют интерфейсы и классы, такие как: PHP, Delphi (Object Pascal), C #.

Приветствия.

umlcat
источник
0

Как правило, вам нужен интерфейс для всего, что передается в качестве параметра или возвращается, по существу, чтобы вы могли отделить класс от его зависимостей.

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

JK.
источник
0

Правила разработки API - это действительно специфическая вещь. Я не уверен, что вы должны сделать какие-либо выводы из этого FAQ с точки зрения того, как вы должны разрабатывать свой повседневный код.

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

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

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

guillaume31
источник