История изменений
Исправление den73, (текущая версия) :
Тему не читал. Главное, что нужно знать об ООП - что это не способ решения всех проблем и не серебряная пуля. А всего лишь инструмент, достаточно несовершенный и выходящий из моды.
1. Два понятия ООП: автономные объекты, сообщения, позднее связывание - из Smalltalk; и наследование, инкапсуляция, полиморфизм - из Модулы 2
2. ООП среди других парадигм. Реляционная парадигма. Полезность SQL сервера состоит в том, что он автоматизирует решение задач (компьютер делает работу за человека). Это свойство не парадигмы, но инструмента. Функциональная парадигма. Полезность чистого ФП - упрощается анализ программ за счёт отсутствия побочных эффектов. Подумать, чем полезна ООП? Что в этом случае компьютер делает за человека? Мой ответ - по сути, ничего не делает, а только лишь заставляет человека следовать определённым соглашениям. Может иметь смысл, для разделения работы - поставщик предоставляет класс, а пользователь его наследует. Однако этот подход устаревает.
3. ООП ортогонально статической типизации (Smalltalk, Python, Common Lisp). Работа с объектами в статической и динамической типизации. Преимущества статической типизации - меньшая неоднозначность текста программы (и ещё другие нагуглить), повышенная эффективность. Преимущества динамической - повышение выразительности и сокращение объёма исходника. Осознать, что виртуальный метод - это частный случай динамической типизации и что он страдает от всех её недостатков.
4. Шаблон проектирования Visitor - не закон природы, а лишь следствие из того, как реализовано ООП конкретно в C++ и Java. Понятие о множественной диспетчеризации.
5. ООП в стиле С++ не так уж сложно реализовать. Реализовать эрзац-ООП на Си с помощью макросов. Должны быть записи с тегом типа, таблицы виртуальных методов. Будет многословно, но по смыслу должно получиться то же, что в С++. Продвинутое упражнение - реализовать ООП со множественной диспетчеризацией, как в CLOS.
6. Отличие наследования от композиции. Рекомендуют применять композицию вместо наследования. Проблема хрупкого базового класса. Но у наследования есть преимущества, которые нельзя игнорировать. В наследовании - общее время жизни, одновременная инициализация, один кусок памяти. Пространство имён методов может не совпадать (при множественном наследовании в С++ можно указывать конкретного предка при вызове метода). Внедрение зависимостей ведь вроде тоже сюда относится?
7. Принцип Лисковой. Перекрытие потомком реализованного предком виртуального метода нарушает его. Добавление поля к классу нарушает его. А нарушение принципа Лисковой затрудняет анализ программы. Отсюда возникают интерфейсы как основной случай ООП. В современных языках (Rust, Golang) вовсе отказались от наследования или сделали его малозаметным (включение). Проблемы многословности в Rust, связанные с этим выбором.
8. Варианты использования ООП без инкапсуляции (CL, а также Scala c public по умолчанию). Противоречие между инкапсуляцией и рефлексией (в Golang только public поля записи можно сериализовать в Json). RTTI. Взлом инкапсуляции через определение идентичного класса и опасное приведение типа.
9. Snit как пример ООП без объектов. Автоматическое делегирование методов средствами метапрограммирования. Средства объектного моделирования (Rational Rose, ныне что-то про неё позабыли, а я успешно прошёл мимо). Осознание, что делать частное поле и потом к нему две функции - это наказание, и плох тот язык, который его не автоматизирует для частных случаев.
10. Насколько я знаю, современные руководства по проектированию говорят о нежелательности глубоких иерархий. В реальности многие крупные проекты содержат глубокие иерархии. В теории, теория и практика согласуются, но на практике они зачастую сильно отличаются.
11. Наследование реализации и таблицы виртуальных методов как способ оптимизации программ. Но ООП находится на более высоком уровне абстракции. Таким образом, в С++ наследование представляет из себя смешение уровней абстракции, это не хорошо и не плохо, но нужно это понимать.
12. Множественное наследование. Я не эксперт по ООП, но вроде как в С++ оно реализовано наиболее общим способом, мне нравится. Ограниченные способы множественного наследования - примеси. Разобраться в терминологии, что называется mixin и trait в разных языках - терминология противоречивая. Составить табличку, в неё должны входить, как минимум PHP, Scala и Haskell (тайпклассы - это интерфейсы). Знать, что в Java ввели множественное наследование спустя ~20 лет, а до этого говорили, что оно не нужно.
13. Проблема алмаза (diamond inheritance, наследование по нескольким путям). Изучить историю борьбы с ним в Scala. Его закапывают, а оно выползает в новом месте. Вероятно, что-то не так с самой идеей.
14. Сортировка методов при множественном наследовании (забыл термин). Применяется в Scala. Вообще говоря, лишняя сущность, произвольное соглашение, созданное только, чтобы искусственным путём разрешить неоднозначность. И тут должно снова закрасться подозрение, что в ООП изначально не всё было гладко.
15. Осознание, что шаблоны классов, дженерики и прочее - это механизм, отдельный от ООП. Сделать вывод о том, что ООП - не такой уж общий механизм.
16. Проблема неродственности TemplateClass<T> для разных T. Ковариантность и контравариантность. По-моему, в С# сделано наиболее толково.
Исходная версия den73, :
Тему не читал. Главное, что нужно знать об ООП - что это не способ решения всех проблем и не серебряная пуля. А всего лишь инструмент, достаточно несовершенный и выходящий из моды.
1. Два понятия ООП: автономные объекты, сообщения, позднее связывание - из Smalltalk; и наследование, инкапсуляция, полиморфизм - из Модулы 2
2. ООП среди других парадигм. Реляционная парадигма. Полезность SQL сервера состоит в том, что он автоматизирует решение задач (компьютер делает работу за человека). Это свойство не парадигмы, но инструмента. Функциональная парадигма. Полезность чистого ФП - упрощается анализ программ за счёт отсутствия побочных эффектов. Подумать, чем полезна ООП? Что в этом случае компьютер делает за человека? Мой ответ - по сути, ничего не делает, а только лишь заставляет человека следовать определённым соглашениям. Может иметь смысл, для разделения работы - поставщик предоставляет класс, а пользователь его наследует. Однако этот подход устаревает.
3. ООП ортогонально статической типизации (Smalltalk, Python, Common Lisp). Работа с объектами в статической и динамической типизации. Преимущества статической типизации - меньшая неоднозначность текста программы (и ещё другие нагуглить), повышенная эффективность. Преимущества динамической - повышение выразительности и сокращение объёма исходника.
4. Шаблон проектирования Visitor - не закон природы, а лишь следствие из того, как реализовано ООП конкретно в C++ и Java. Понятие о множественной диспетчеризации.
5. ООП в стиле С++ не так уж сложно реализовать. Реализовать эрзац-ООП на Си с помощью макросов. Должны быть записи с тегом типа, таблицы виртуальных методов. Будет многословно, но по смыслу должно получиться то же, что в С++. Продвинутое упражнение - реализовать ООП со множественной диспетчеризацией, как в CLOS.
6. Отличие наследования от композиции. В наследовании - общее время жизни, одновременная инициализация, один кусок памяти. Пространство имён методов может не совпадать (при множественном наследовании в С++ можно указывать конкретного предка при вызове метода). Внедрение зависимостей ведь вроде тоже сюда относится?
7. Принцип Лисковой. Перекрытие потомком реализованного предком виртуального метода нарушает его. Добавление поля к классу нарушает его. А нарушение принципа Лисковой затрудняет анализ программы. Отсюда возникают интерфейсы как основной случай ООП. В современных языках (Rust, Golang) вовсе отказались от наследования или сделали его малозаметным (включение).
8. Варианты использования ООП без инкапсуляции (CL, а также Scala c public по умолчанию). Противоречие между инкапсуляцией и рефлексией (в Golang только public поля записи можно сериализовать в Json). RTTI. Взлом инкапсуляции через определение идентичного класса и опасное приведение типа.
9. Snit как пример ООП без объектов. Автоматическое делегирование методов средствами метапрограммирования. Средства объектного моделирования (Rational Rose, ныне что-то про неё позабыли, а я успешно прошёл мимо). Осознание, что делать частное поле и потом к нему две функции - это наказание, и плох тот язык, который его не автоматизирует для частных случаев.
10. Насколько я знаю, современные руководства по проектированию говорят о нежелательности глубоких иерархий. В реальности многие крупные проекты содержат глубокие иерархии. В теории, теория и практика согласуются, но на практике они зачастую сильно отличаются.
11. Наследование реализации и таблицы виртуальных методов как способ оптимизации программ. Но ООП находится на более высоком уровне абстракции. Таким образом, в С++ наследование представляет из себя смешение уровней абстракции, это не хорошо и не плохо, но нужно это понимать.
12. Множественное наследование. Я не эксперт по ООП, но вроде как в С++ оно реализовано наиболее общим способом, мне нравится. Ограниченные способы множественного наследования - примеси. Разобраться в терминологии, что называется mixin и trait в разных языках - терминология противоречивая. Составить табличку, в неё должны входить, как минимум PHP, Scala и Haskell (тайпклассы - это интерфейсы). Знать, что в Java ввели множественное наследование спустя ~20 лет, а до этого говорили, что оно не нужно.
13. Проблема алмаза (diamond inheritance, наследование по нескольким путям). Изучить историю борьбы с ним в Scala. Его закапывают, а оно выползает в новом месте. Вероятно, что-то не так с самой идеей.
14. Сортировка методов при множественном наследовании (забыл термин). Применяется в Scala. Вообще говоря, лишняя сущность, произвольное соглашение, созданное только, чтобы искусственным путём разрешить неоднозначность. И тут должно снова закрасться подозрение, что в ООП изначально не всё было гладко.
15. Осознание, что шаблоны классов, дженерики и прочее - это механизм, отдельный от ООП. Сделать вывод о том, что ООП - не такой уж общий механизм.
16. Проблема неродственности TemplateClass<T> для разных T. Ковариантность и контравариантность. По-моему, в С# сделано наиболее толково.