Александр Головня

+18
с 2021

Инженер-программист, консультант и лектор. Проектирую архитектуру и разрабатываю высоконагруженные системы в здравоохранении, телекоме и финтехе.

12 подписчиков
41 подписка

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

Второй сценарий — это предоставление базовой реализации для связанных классов. Да, интерфейсы поддерживает методы по-умолчанию и локальные переменные, но это подходит для решения только самых тривиальных задач. К примеру, мы не можем использовать внедрение зависимостей (DI) в интерфейсе, а это является ключевой частью любого промышленного приложения. Поэтому лучшей практикой при предоставлении базового функционала является либо использование абстрактных классов, либо использование композиции.

11

Постараюсь ответить кратко, потому что про сценарии использования можно написать целую отдельную статью :)

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

Другой пример, когда однозначно нужно использовать интерфейс — это реализация так называемых признаков и маркеров. Например, если вам нужно сравнивать объекты, вы можете реализовать интерфейс "Comparable" чтобы быть уверенным, что класс поддерживает сравнение. В свою очередь интерфейс "Cloneable", который является маркером, будет просто означать что ваш тип поддерживает клонирование.

11

Спасибо, а про что интереснее/приоритетнее было бы почитать?

Хороший вопрос! С одной стороны да, если задуматься по логике, то в чем смысл sealed класса или интерфейса если все можно легко обойти? Но если посмотреть в стандарт JEP 409, то можно заметить, что создатели языка не преследовали цели предоставить новый модификатор доступа:
1. «It is not a goal to provide new forms of access control such as "friends"»
2. «It is not a goal to change final in any way.»

Sealed класс/интерфейс дает более гибкий контроль над наследованием. Он может быть наследован только ограниченным заранее определенным набором других классов. Это позволяет нам контролировать наследование в иерархии классов, но при этом давая возможность подклассам самим решать вопрос дальнейших ограничений. Главная цель здесь — это предотвратить непреднамеренное или некорректное наследование, что делает более ясной структуру нашей программы. Это также может помочь компилятору Java делать некоторые оптимизации, поскольку он может быть уверен в иерархии классов.

Если нам нужно гарантировать, что поведение класса не будет изменено через наследование, то нужно использовать модификатор final для класса, что полностью заблокирует дальнейшее наследование. В этой статье, классы Circle и Rectangle, наследующие от sealed класса Shape, как раз и объявлены финальными.

22