Написать эту статью меня побудило 2 фактора: статья «Когда я говорил», берущая за душу, и опыт проведения собесодований, леденящий душу. К сожалению, даже для людей со значительным опытом в разработке, вопрос «чем отличается абстрактный класс от интерфейса?» может стать поводом для несвязной речи и покраснения лица. Чтобы дать возможность людям избежать «этого неловкого момента» и строить грамотную архитектуру приложения (ниже будет пояснено, почему осведомленность в этом вопросе может повлиять на вашу арихитектуру) я решил осветить эту тему.

Сводная таблица

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

Критерий сравнения Абстрактный класс Интерфейс
Наследование Любой класс может наследовать только один абстрактный класс. Любой класс может реализовывать (имплементировать, наследовать) множество интерфейсов.
Модификаторы доступа методов К неабстактным членам класса применимы любые модификаторы. НО! Абстрактные методы (имеющие модификатор abstract) могут иметь модификатор либо public, либо protected. То есть абстрактные методы не могут быть приватными (ну да, а смысл?). Методы в интерфейсе могут иметь модификаторы только public и abstract. По умолчанию они уже public abstract.
Данные Абстрактный класса может содержать любые поля: статические и экземплярные, константы, private/protected/public. Интерфейс может содержать только общедоступные константы (public final static int NOT_PI_CONST = -1);
Наличие реализации Абстактный класс допускает реализацию методов. Интерфейс не может содержать никакой реализации методов.
Возможность описать конструктор В абстрактом классе можно описать конструктор (или несколько конструкторов). В интерфейсе нельзя описать конструктор.

Что выбрать?

В силу отсутствия множественного наследования, к выбору между интерфейсом и абстрактным классом нужно относиться ответсвенно. Но это лишь одна из причин. Используя абстракный класс вы можете сделать вызов метода предка super и получать доступ к его protected полям, что может привести к нарушению инкапсуляции. Поэтому часто рекомендуют использовать вместо наследования композицию или делегирование. Но это рекомендации.

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

Заключение

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *