Страницы

Поиск по вопросам

суббота, 30 ноября 2019 г.

Что правильнее использовать, абстрактный класс, в котором все методы абстрактные или несколько интерфейсов?

#ооп


Например, есть абстрактный класс АбстрактныйАвтомобиль.
У него есть 4 метода - повернутьНалево(), повернутьНаправо(), начатьДвижение(), затормозить().
Есть 3 наследника - ШевролеКруз, ШевролеЛанос и ФордМондео. Я не разбираюсь в автомобилях,
но предположим что поворот руля налево, поворот руля направо, начала движения и торможение
для разных марок автомобилей реализовано по-разному. То есть мы не можем реализовать
ни один из методов в классе АбстрактныйАвтомобиль. Придется их все сделать абстрактными.
А в классах ШевролеКруз, ШевролеЛанос, и ФордМондео реализовать эти методы для каждого
по-своему. Или же правильнее объявить 3 интерфейса - Turnable с методами повернутьНалево()
и повернутьНаправо(), Startable с методом начатьДвижение() и Stopable с методом затормозить()?

Читал, что нужно мыслить на уровне интерфейсов, а не классов. И что вообще абстрактный
класс, в котором есть только абстрактные методы - плохой тон. С другой стороны читал
что если есть отношение является то нужно использовать наследование. А тут явно есть
отношение является.
Что же тут правильнее использовать?
Растолкуйте пожалуйста.

UPD: Написали, что есть дубликат моего вопроса, вот он:
Отличия абстрактного класса от интерфейса (abstract class and interface)
По-моему это все-таки не совсем то..
Там просто разбираются отличия абстрактного класса от интерфейса. Я перечитал много
таких статей прежде чем задавать вопрос. Если бы они для меня все прояснили, я бы его
и не стал задавать. Мне была интересна именно ситуация, когда и отношения является
есть и связь между классами, но при этом абстрактный класс вынужден иметь только абстрактные
методы. Конечно я понимаю, что если в классах 10 методов реализовываются одинаково
а один нет, то надо применять наследование. А вот в описанной выше ситуации я не понимал
что нужно делать.
    


Ответы

Ответ 1



Прелесть интерфейсов в вашем контексте вы оцените, когда у вас появится другое транспортное средство, например мотоцикл. К примеру у вас будет интерфейс: public interface Movable{ public void Move(); } Тогда, вы можете реализовать в нужных классах его, что будет обозначать, что средство может двигаться. Теперь вы можете в одну коллекцию сложить разные классы List, где могут быть и мотоциклы, и машины. В случае с абстрактным классом у вас бы такое не получилось. Проблема, лично для меня, абстрактных классов в том, что при использование вы завязываетесь на конкретную реализацию. И что вообще абстрактный класс, в котором есть только абстрактные методы - плохой тон. Это вообще бессмысленно. Делать абстрактный класс имеет смысл, если у вас много общей логики, которую вы в него вынесите.

Ответ 2



Вы должны различать интерфейсы — средства проектирования классов, и абстрактные классы — средство имплементации, повторного использования кода. С точки зрения системы типов, коду, который пользуется вашими классами, начхать, одинаково ли устроен метод ПовернутьНаправо у классов Бэха и Фордфокус. Им главное, что эти методы существуют. Поэтому наружу должен быть виден интерфейс, который гарантирует существование нужных методов. Теперь, с точки зрения имплементации, которая есть сугубо ваша внутренняя кухня, вы можете заметить, что ШевролеКруз и ШевролеЛанос в силу текущих подробностей реализации рулят налево совершенно одинаково. Вот вы, чтобы не копипастить код, помещаете общий метод в абстрактный суперкласс, и таким образов расшариваете его между двумя имплементациями. Таким образом, для внешнего клиента важен интерфейс. А вот для эффективной имплементации вы вполне можете воспользоваться абстрактными классами. (Но объясните пользователю, что абстрактные классы — ваша приватная штука, и их иерархия может поменяться при первом же рефакторинге.) В свете этого становится понятно, почему прохладно относятся к абстрактным классам без методов. Если у вас есть такой класс, но не служит делу повторного использования кода, то он, скорее всего, и не нужен. Однако: в некоторых языках (например, C++), понятия интерфейса нету вовсе. Вот в них-то и приходится эмулировать интерфейс при помощи пустых абстрактных классов. Отдельный вопрос — выстраивание иерархии классов. Вам может понадобиться общий предок нескольких классов, если он несёт свою смысловую нагрузку в программе. А вот создание общего предка лишь для того, чтобы передавать разные объекты в общую функцию — не очень верная идея, лучше для этого использовать интерфейсы.

Ответ 3



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

Комментариев нет:

Отправить комментарий