Недостаток ООП? [закрытый]

39
задан bragboy 6 July 2012 в 13:08
поделиться

16 ответов

Я не совсем понимаю его пример.

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

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

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

Что касается вашего последнего вопроса «Можем ли мы отключить иерархии классов в идеальном объектно-ориентированном дизайне?», Я не уверен, что вы здесь имеете в виду. Если вы спрашиваете об изменении иерархии во время выполнения и о том, чтобы отношения подтипов больше не существовали в какой-то момент выполнения, тогда да. Это возможно с некоторыми языками, такими как Smalltalk. Некоторые возразят, что это «Больше ООП».В smalltalk «методы», поддерживаемые типом, определяются в точке вызова метода на основе текущей иерархии и текущего содержимого каждого класса. Хотя я люблю smalltalk, это одна функция, от которой я не без ума, так как я предпочитаю проверку во время компиляции с меньшими неожиданностями во время выполнения.

19
ответ дан 27 November 2019 в 02:14
поделиться

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

Например, у нас есть классы A, B, C и D. Класс A имеет классы методов B , C и D нужны. У класса B есть методы, которые нужны классу D. Итак, мы могли бы получить класс D из B и B из A. С другой стороны, мы получим C из A, потому что C не нужно то, что есть у B. Таким образом, мы в основном решили проблему с ненужным материалом, добавив один дополнительный класс в иерархию. Конечно, если бы что-то подобное не было уловлено на этапе планирования и класс B использовался в качестве базового, было бы сложнее разделить класс B на два класса, но с некоторыми дополнительными усилиями проблема ненужного багажа будет решена.

1
ответ дан 27 November 2019 в 02:14
поделиться

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

Я не могу знать, как интервьюер поставил вопрос или как вы ответили, но один из самых больших недостатков ООП на самом деле не ООП сам по себе. Это плохое использование ООП и плохие отношения «IS-A», которые люди пытаются создать. Если единственная причина, по которой вы можете создать иерархию наследования, - это повторное использование кода, это плохая причина. Можно утверждать, что АОП является лучшим подходом для этого. (перед тем как проголосовать против или проголосовать против, обратите внимание, что я сказал «может быть»)

ООП касается интерфейса и типа, а не реализации. Все, что мне нужно знать, - это знать, что объект может возвращать список кандидатов на работу. Неважно, исходит ли это из РСУБД, БД, ориентированного на столбцы, веб-службы или даже из электронной таблицы. Я знаю, что могу передать этот объект в качестве параметра другим методам, и они могут вызвать «FetchJobCandidates» и знать, что он получит кандидатов на работу. На этом пути есть подводные камни, но в основном, если вы думаете о классах, основанных на том, что они открывают для остального мира, а не на том, что они делают внутри, вы находитесь в лучшем положении, ИМО.

1
ответ дан 27 November 2019 в 02:14
поделиться

Хотя я не совсем понимаю приведенный пример, поскольку для меня это звучит как композиция, я приведу недостаток ООП

ОО трудно протестировать

  • Нет прямого доступа к переменным / атрибутам класса для чтения / записи - может потребоваться ввести геттеры и поисковики, которые нарушают инкапсуляцию.

  • Наследование может изменить поведение метода в подклассе

  • Объекты имеют состояние. Сгенерировать эти состояния может быть сложно, поскольку мы зависим от общедоступного интерфейса.

  • Классы со связностью loh могут быть трудными для тестирования, поскольку это может означать, что класс делает больше, чем указано.

9
ответ дан 27 November 2019 в 02:14
поделиться

Его пример не имеет смысла. Ракета не наследуется от тела. У него есть тело. Это сдерживание. Так что в какой-то момент вы могли бы «удалить» часть, прикрепленную к ракете, когда она была выброшена.

11
ответ дан 27 November 2019 в 02:14
поделиться

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

Тем не менее, люди хорошо критикуют ООП. Например, Казнь Стива Йегге в Царстве существительных .

15
ответ дан 27 November 2019 в 02:14
поделиться

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

Думаю, ваш идеал космического корабля для интервьюера - это Черный обелиск из 2001: Космическая одиссея .

1
ответ дан 27 November 2019 в 02:14
поделиться

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

1
ответ дан 27 November 2019 в 02:14
поделиться

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

Вкратце:Полиморфизм можно сделать не явным и, таким образом, легко упустить из виду странное поведение в производных классах.

1
ответ дан 27 November 2019 в 02:14
поделиться

Можем ли мы просто сказать, использовать это в ООП?

RocketShip.BodyPart1 = ничего или

RocketShip.BodyPart1.isDetached = false?

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

1
ответ дан 27 November 2019 в 02:14
поделиться

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

1
ответ дан 27 November 2019 в 02:14
поделиться

Классика состоит в том, чтобы предпочесть композицию наследованию. Наследование существует для того, чтобы фиксировать абстракции вдоль шва, по которому изменяется ваша система.

Если вы не совсем четко фиксируете эту абстракцию, то да, вы получите странные силы на ваших конструкциях. Но это проблема программирования в мире, где абстракции не совсем подходят для того, чего вы пытаетесь достичь. Не то чтобы они когда-либо были совершенны.

1
ответ дан 27 November 2019 в 02:14
поделиться

Может быть, в примере с ракетой упоминается тот факт, что во многих объектно-ориентированных языках тип объекта неизменен? То есть, если у меня есть объект Student , и человек, который он представляет, заканчивает учебу и становится сотрудником, я не могу превратить объект Student в Employee ] объект. Мне нужно создать новый, потерять идентичность объекта в процессе и, следовательно, обновить все ссылки, указывающие на бывшего ученика.

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

2
ответ дан 27 November 2019 в 02:14
поделиться

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

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

3
ответ дан 27 November 2019 в 02:14
поделиться

Просто потому, что у вас есть молоток, не означает, что все - гвоздь.

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

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

Но давайте рассмотрим суть вопроса интервьюеров: когда ООП является неудачным выбором парадигмы? .

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

В конечном счете, ООП-программирование также требует определенного уровня строгости проектирования и планирования, а также понимания основных принципов объектной ориентации . Если вы не желаете тратить время на изучение и понимание этих принципов ... ну, возможно, тогда ООП-программирование не для вас.

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

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

34
ответ дан 27 November 2019 в 02:14
поделиться

Одним из способов моделирования объекта, который меняет свой подкласс, является использование шаблона состояния . Используя ваш вопрос на собеседовании и некоторую помощь из Википедии , вот некоторый код Java, который показывает, как вы можете моделировать переходы между состояниями, когда ракета проходит различные стадии. Я не показывал этапы командного модуля, но они следуют аналогичной схеме через лунный спуск, лунный подъем, сближение на лунной орбите и возвращение на Землю. Вероятно, вы могли бы найти гораздо более интересные варианты поведения, которые можно было бы добавить в интерфейс ISpaceShipState.

public class SpaceShip {
    private ISpaceShipState m_state = new SaturnFiveState();

    public void setState(ISpaceShipState state) {
        m_state = state;
    }

    public void jettison() {
        m_state = m_state.transition();
    }

    public int getStageNumber() {
        return m_stage.getStageNumber();
    }

    public int getNumberOfRocketMotors() {
        return m_stage.getNumberOfRocketMotors();
    }

    public String getRocketMotorTypeName() {
        return m_stage.getRocketMotorTypeName();
    }
}

interface ISpaceShipState {
    public ISpaceShipState transition();
    public int             getStageNumber();
    public int             getNumberOfRocketMotors();
    public String          getRocketMotorTypeName();
}

public class SaturnFiveState implements ISpaceShipState {
    public ISpaceShipState transition() {
        return new SaturnFiveSecondStageState();
    }

    public int getStageNumber() {
        return 1;
    }

    public int getNumberOfRocketMotors() {
        return 5;
    }

    public String getRocketMotorTypeName() {
        return "F-1";
    }
}

public class SaturnFiveSecondStageState implements ISpaceShipState {
    public ISpaceShipState transition() {
        return new SaturnFiveThirdStageState();
    }

    public int getStageNumber() {
        return 2;
    }

    public int getNumberOfRocketMotors() {
        return 5;
    }

    public String getRocketMotorTypeName() {
        return "J-2";
    }
}

public class SaturnFiveThirdStageState implements ISpaceShipState {
    public ISpaceShipState transition() {
        return new SaturnFiveCommandModuleState();
    }

    public int getStageNumber() {
        return 3;
    }

    public int getNumberOfRocketMotors() {
        return 1;
    }

    public String getRocketMotorTypeName() {
        return "J-2";
    }
}

Можем ли мы отключать иерархии классов динамически (я уверен, что в Java это невозможно) в идеальном объектно-ориентированном дизайне?

Можно смоделировать динамическую типизацию в Java с помощью отражения, хотя код очень неуклюжий по сравнению с тем же самым в языке с динамической типизацией.

1
ответ дан 27 November 2019 в 02:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: