Действительно ли наследование необходимо? - PullRequest
32 голосов
/ 10 ноября 2008

Должен признаться, я отчасти скептик ООП. Плохой педагогический и лабораторный опыт с объектной ориентацией не помог. Таким образом, я превратился в горячего сторонника Visual Basic (классического!).

Затем однажды я узнал, что C ++ изменился и теперь имеет STL и шаблоны. Мне действительно понравилось это! Сделал язык полезным. Затем в другой день MS решила применить лицевую хирургию к VB, и я действительно ненавидела конечный результат за необоснованные изменения (использование «end while» вместо «wend» сделает меня лучшим разработчиком? Почему бы не бросить «next» для » конец для "тоже? Зачем заставлять геттер вместе с сеттером? И т. д.) плюс так много функций Java, которые я нахожу бесполезными (например, наследование и концепция иерархической структуры).

И теперь, спустя несколько лет, я задаю себе философский вопрос: действительно ли необходимо наследование ?

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

Есть идеи? Я хотел бы видеть пример, где наследование определенно будет необходимо, или где использование наследования вместо интерфейсов композиции + может привести к более простому и легкому изменению дизайна. В предыдущих заданиях, которые я обнаружил, если вам нужно изменить базовый класс, вам нужно также изменить почти все производные классы, поскольку они зависят от поведения родительского класса. И если вы сделаете методы базового класса виртуальными ... тогда не будет большого совместного использования кода: (

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

Ответы [ 22 ]

2 голосов
/ 10 ноября 2008

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

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

2 голосов
/ 10 ноября 2008

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

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

Наследование часто используется в качестве опоры людьми, которые слишком одержимы узким определением Java (и одержимость) ООП, хотя, и в большинстве случаев я согласен, что это неправильное решение, как если бы глубже ваша иерархия классов, лучше ваше программное обеспечение.

2 голосов
/ 10 ноября 2008

номер

для меня ООП - это в основном инкапсуляция состояния, поведения и полиморфизма.

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

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

1 голос
/ 07 ноября 2016

Наследование и Композиция имеет свои плюсы и минусы.

Обратитесь к этому связанному SE вопросу о плюсах наследования и минусах композиции.

Предпочитаете композицию наследованию?

Посмотрите на пример в этой ссылке на документацию :

В примере показаны различные варианты переопределения с использованием наследования в качестве средства для достижения полиморфизма.

1 голос
/ 30 марта 2013

// Я нашел этот QA очень полезным. Многие ответили на это право. Но я хотел добавить ...

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

2: Наследование помогает типам моделей очень близки к их фактическим отношениям. Иногда много ошибок обнаруживается во время компиляции, потому что у вас правильная иерархия типов. Например, shape <-- triangle (допустим, много кода можно использовать повторно). Возможно, вы захотите составить треугольник с shape объектом, но shape является неполным типом. Вставка фиктивных реализаций, подобных double getArea() {return -1;}, подойдет, но вы открываете пространство для ошибок. Это return -1 может быть выполнено когда-нибудь!

3: void func(B* b); ... func(new D()); Неявное преобразование типов обеспечивает большое удобство записи, поскольку Derived равно Base. Я помню, как читал Страуструпа, говоря, что он хотел сделать классы первоклассными гражданами, как базовые типы данных (отсюда перегрузка операторов и т. Д.). Неявное преобразование из Derived в Base ведет себя так же, как неявное преобразование из типа данных в более совместимый (сокращенно в int).

1 голос
/ 05 января 2010

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

Использовать базовый класс (не абстрактный), от которого могут наследовать другие программисты (и при необходимости переопределять методы); затем добавьте метод к нему. Каждое приложение, использующее ваш класс, все еще будет работать, этот метод никем не будет переопределен, но, поскольку вы предоставляете базовую реализацию, она будет использоваться, и она может прекрасно работать для всех подклассов вашего класса ... также вызывает странное поведение, потому что иногда это необходимо было бы переопределить, хорошо, может быть, дело в этом, но по крайней мере все эти миллионы приложений в мире по-прежнему будут запускаться!

Я предпочитаю, чтобы мое Java-приложение все еще работало после обновления JDK с 1.6 до 1.7 с некоторыми незначительными ошибками (которые могут быть исправлены с течением времени), вместо того, чтобы вообще не запускать его (вызывая немедленное исправление, иначе оно бесполезно чел.)

1 голос
/ 11 ноября 2008

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

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

Видя некоторые ответы, в которых упоминается нечто подобное, я задаюсь вопросом, может ли это быть не совсем так, как предполагается использование наследования: ex post facto. Напоминает мне цитату Степанова: «Вы начинаете не с аксиом, вы заканчиваете аксиомами после того, как у вас есть куча связанных доказательств». Он математик, поэтому он должен что-то знать.

1 голос
/ 10 ноября 2008

Наследование - хорошая вещь, когда подкласс действительно тот же тип объекта, что и суперкласс. Например. если вы реализуете шаблон Active Record, вы пытаетесь сопоставить класс с таблицей в базе данных, а экземпляры класса - с строкой в ​​базе данных. Следовательно, весьма вероятно, что ваши классы Active Record будут иметь общий интерфейс и реализацию методов, таких как: каков первичный ключ, сохраняется ли текущий экземпляр, сохраняет текущий экземпляр, проверяет текущий экземпляр, выполняет обратные вызовы после проверки и / или сохранение, удаление текущего экземпляра, выполнение SQL-запроса, возвращение имени таблицы, к которой относится класс, и т. д.

Из того, как вы формулируете свой вопрос, также видно, что вы предполагаете, что наследование одно, а не множественное. Если нам нужно множественное наследование, то мы должны использовать интерфейсы и композицию, чтобы выполнить работу. Чтобы подчеркнуть это, Java предполагает, что наследование реализации является единичным, а наследование интерфейса может быть множественным. Не нужно идти по этому пути. Например. C ++ и Ruby разрешают множественное наследование для вашей реализации и вашего интерфейса. При этом следует с осторожностью использовать множественное наследование (т. Е. Сохранять свои абстрактные классы виртуальными и / или не сохраняющими состояния).

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

1 голос
/ 10 ноября 2008

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

Или вы можете сделать новую лампу с нуля или попросить людей взглянуть на нее определенным образом, чтобы увидеть свет, или, или, или

Не обязательно, но приятно:)

1 голос
/ 10 ноября 2008

Я согласен со всеми остальными в отношении необходимого / полезного различия.

Причина, по которой мне нравится ООП, заключается в том, что он позволяет мне писать код, который чище и более логично организован. Одно из самых больших преимуществ заключается в способности «разукрупнять» логику, которая характерна для ряда классов. Я мог бы привести вам конкретные примеры, когда ООП серьезно снизил сложность моего кода, но это было бы скучно для вас.

Достаточно сказать, я сердечно ООП.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...