- Методологии программирования
- Процедурное
- Модульное
- Объектное
- Объектно-ориентированное
- Объекты и классы
- Принципы объектно-ориентированного программирования
- Абстракция
- Инкапсуляция
- Иерархия
- Модульность
- Полиморфизм
- Типизация
- Параллелизм
- Сохраняемость
- Принципы объектно-ориентированного проектирования
- Принцип единственности абстракции
- Принцип инверсии зависимости
- Принцип подстановки Лисковой
- Принцип разделения интерфейсов
- Принцип ацикличности зависимостей
Процедурная - когда нужно декомпозировать задачу на набор функций и реализовать их.
Модульная - когда программа определяется на какие-то составные компоненты, которые реализуют её (так в Python).
Объектная - когда есть какие-то объекты и мы их описываем (моделирование из реального мира), что позволяет нам мыслить в более человеческих терминах
Объектно-ориентированная - продолжение объектного, так как потребовалось обобщение этих объектов (на данный момент, самый распространённый подход).
Объектно-ориентированное программирование обеспечивает:
- расширяемость системы (extensibility)
- лёгкость поддержки системы в дальнейшем (maintainability)
- создание переиспользуемых компонент (reusability)
Объект - сущность, обладающая идентичностью, поведением и состоянием.
Состояние является результатом суммарного поведения.
Класс это множество объектов с общим поведением и состоянием.
Абстракция - это отделение существенных свойств объекта от несущественных. Не стоит путать с абстрактными классами.
Граница - является барьером абстракции. Он защищает от избыточной сложности, т. е. позволяет декомпозировать сущности на что-то небольшое.
Инкапсуляция - это разделение интерфейса и реализации.
Интерфейс - контракт, определяющий, какие сообщения может принимать объект (= какие методы можно вызывать у нашего объекта / что можно делать с этим объектом). Контракт не зависит от реализации, что позволяет обеспечивать слабую связность между компонентами. Иначе говоря, чтобы поменять одну часть кода, не придётся переписывать весь код.
Иерархия - упорядочение сущностей по уровням. Она позволяет декомпозировать сложные сущности из реального мира постепенно повышая детализацию. Например:
- Иерархия наследования классов
- Иерархия объектов
- Иерархия модулей
Например:
Самолёт - Двигатель + Фюзеляж + Шасси + Крылья + Хвостовое оперенье.
Двигатель - цилиндр + система сжигания + стартер и т. д
По сути, спускаясь вниз, на каждом уровне мы детализируем общий объект.
Модульность это разделение программы на тесно связанные внутри и слабо связанные снаружи модули
Полиморфизм - механизм, позволяющий придать программе контекстно зависимую семантику. Проще говоря, код написан один и тот же, но в зависимости от разного контекста выполняет разные действия. Он может быть статическим или динамическим, позволяет описывать какие-то обобщённые алгоритмы.
Типизация - механизм, позволяющий защищаться от использования объектов одного типа вместо объектов другого типа или по, крайней мере, управлять таким использованием. Может быть статической (раннее связывание, на этапе компиляции) и динамической (позднее связывание, например как в Python), строгой и слабой.
В основном, в C++ статическая типизация (но присутствует и динамическая в виртуальном полиморфизме).
Строгая типизация означает, что мы никогда не можем использовать объекты одного типа вместо объектов другого типа. Слабая означает, что все объекты неявно приводятся друг к другу.
Параллелизм - возможность иметь несколько активных объектов.
Сохраняемость - способность объекта существовать во времени, переживая породивший его процесс, и (или) в пространстве, перемещаясь из своего первоначального адресного пространства.
Класс должен обладать единственной ответственностью, реализуя её полностью, реализуя её хорошо и реализуя только её. Например, если класс Image не только работает с самим изображением, но ещё и сериализует данные (то что не входит в ответственность класса работы с изображением).
При нарушении данного принципа ваш код становится менее переиспользуемым, т. е появляется привязка к каким-то деталям (например, привязка только лишь к формату BMP в классе Image); добавляются лишние зависимости в коде.
Модули высокого уровня не должны зависеть от модулей низкого. И те, и другие, должны зависеть от абстракций. Абстракции не должны зависеть от деталей реализации.
Каждый элемент программы должен обладать ограниченным знанием о других элементах и использовать только тесно связанные с ним элементы. Этот принцип говорит, что надо писать код так, чтобы каждый метод / класс обладал ограниченным знанием о других (локализация). Иначе говоря, если все классы и методы знают про друг-друга, то в графе зависимости они связаны между собой, а следовательно изменение одного элемента, повлечёт изменение и других, что не есть хорошо.
Методы, принимающие в качестве параметра указатели и ссылки на объекты базового класса должны иметь возможность использовать эти объекты без необходимости знать к какому классу (базовому или любому из производных) они принадлежат. Он нужен для работы полиморфизма и описание базовых интерфейсов.
Примером нарушения этого принципа является наследование квадрата от прямоугольника (в зависимости от типа, переданного в функцию для вычисления площади работало по-разному). В качестве самопроверки можно попробовать подставить какой-нибудь класс-наследник, вместо того, что вы ожидаете или dynamic_cast.
Классы не должны зависеть от контрактов, которых они не используют. Проще говоря, классы не должны “платить” за те интерфейсы, которыми не пользуются.
Структура зависимостей между элементами (классами, пакетами, методами) должна представлять собой направленный ациклический граф**.**