Полиморфизм/динамическая привязка, суперкласс или интерфейс?

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

Таким образом, A, B, C, D происходят от S, а S реализует I.

Я мог бы сделать:

S a = new A();
S b = new B();

or

I a = new A();
I b = new B();

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


person user997112    schedule 14.07.2012    source источник
comment
Почти всегда лучше объявлять переменные как тип интерфейса, что дает вам больше гибкости. В противном случае вы ограничиваете конкретные типы только суперклассом. Что, если позже вы захотите использовать для тестирования совершенно другой макетный класс? Если вы используете суперкласс, вы можете застрять.   -  person Hovercraft Full Of Eels    schedule 14.07.2012
comment
Если абстрактный суперкласс добавляет что-то, что вам нужно, на что нет ссылок в интерфейсе, например метод, не указанный в интерфейсе, или поле, на которое вам нужно будет ссылаться, поместите их в переменную типа суперкласса. Если вам не нужны какие-либо дополнительные функции, предлагаемые суперклассом, используйте интерфейс. Если суперкласс вообще не предлагает никакой новой функциональности, он вам не нужен, и вы должны просто сделать так, чтобы A и B реализовывали I напрямую.   -  person CosmicComputer    schedule 14.07.2012


Ответы (2)


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

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

С точки зрения реализации кода у этих двух подходов есть свои преимущества и недостатки:

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

  • Вы пытаетесь использовать внешний API для реализации таким образом, что это ограничивает вашу способность писать новые реализации. Класс java.io.OutputStream является классическим примером этого. Поскольку это класс, вам нужно создать подкласс, чтобы реализовать новый тип потока, и вы можете обнаружить, что вам нужно закодировать подкласс, чтобы переопределить всю инфраструктуру, которую вы «наследуете».

  • Тот факт, что у класса может быть только один суперкласс, еще больше ограничивает вас древовидной иерархией API.

  • Клиенты должны быть закодированы в соответствии с API-интерфейсами класса реализации в большей степени... потому что это все, что есть. И это ограничивает возможность программиста передумать.


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


Должен добавить, я не спрашиваю, использовать интерфейсы или нет. Я предполагаю, что интерфейсы можно использовать только для того, чтобы заставить кого-то реализовать методы (и никогда не объявлять их как тип)?

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

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

Я просто спрашиваю, какие преимущества дает использование интерфейсов в качестве типа объекта для полиморфизма?

Из уровней набора и производительности: нет - см. выше.

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

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

person Stephen C    schedule 14.07.2012
comment
Должен добавить, я не спрашиваю, использовать интерфейсы или нет. Я предполагаю, что интерфейсы можно использовать только для того, чтобы заставить кого-то реализовать методы (и никогда не объявлять их как тип)? Я просто спрашиваю, какие преимущества дает использование интерфейсов в качестве типа объекта для полиморфизма? - person user997112; 14.07.2012

Это полностью зависит от контекста.

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

person Tony R    schedule 14.07.2012