Вы находитесь на странице: 1из 56

Основы объектно-

ориентированного
программирования

Чернойван Василий Александрович


vchernoivan@gmail.com
http://chernoivan.ru/oop/
Как писать «хороший»
код?
Code Smells
…или что такое «хорошо» и
что такое «плохо»
Ваш код читают люди

Ваша цель — быть понятными


Комментарии
• Отсутствие в интерфейсах классов и модулей
– Действительно ли все понятно только по
сигнатуре?
– Любые значения параметров допустимы и
равнозначны?
– Любые возвращаемые значения допустимы и
равнозначны ?
– Нет никаких специальных случаев и
исключительных ситуаций?
Комментарии
Комментарии
Комментарии
Комментарии
• Наличие в реализациях
– Ваши комментарии отвечают на вопросы «что?» и
«как?»?
– Ваши комментарии поясняют что-то неочевидное
из прочтения на C++?
– Можно ли переписать Ваш код так, чтобы
комментарии были не нужны?
Комментарии
Дублирующийся код
Дублирующийся код
Решение: определить функцию (метод)
Дублирующийся код

Необязательно код дублируется дословно.

Часто бывает, что одну и ту же задачу решают


несколькими похожими способами.

Нужно выбрать один!


Длинный метод
Длинная функция (метод)
Длинный кусок кода сложнее для чтения и понимания
(при прочих равных).

Решение: декомпозиция
• Самое простое — декомпозиция на понятные по
смыслу операции (ф-и и методы) и наименование
их соответствующим образом
• Возможны и более сложные декомпозиции, такие,
как мы применили в случае разбиения на команды
Сложные логические структуры (if/else switch/case
for/while)

● Большое количество
● Большая вложенность
● А ТАКЖЕ ОПЕРАТОР goto!
● Решение: все то же самое — декомпозиция
Длинный список параметров
одержимость примитивами
Длинный список параметров
• Скорее всего либо неправильно декомпозирован
метод, либо неправильно выбраны параметры
• Решение
– Разделить метод на несколько с меньшим
количеством параметров
– Объединить параметры в сущность более
высокого уровня
• Одержимость примитивами или связки
данных
– Если примитивные данные появляются все время
«в связке», вероятно, они принадлежат друг
другу?
– Не используйте примитивные типы данных как
«босяцкую» замену классам. Если данные
сложны, напишите класс
Чрезмерное использование
литеральных констант

Commands.
Чрезмерное использование
литеральных констант

Или разного рода «Волшебных чисел», «Волшебных


строк» и т. п.
• Сложно отлавливать опечатки
• Ухудшает читаемость текста
• Затрудняет перевод

• Решение: используйте именованные константы


Идентификаторы

• Чрезмерно длинные
• Чрезмерно короткие
• И то и другое затрудняет читаемость кода.
Идентификаторы должны быть с одной стороны,
читаемы, с другой – понятными.
• Имена объектов должны объяснять, для чего нужны
объекты
Идентификаторы
Принципы ООП
Принципы здравого смысла
Don't-Repeat Yourself
(не повторяйся)

• Любая информация (часть знания) должна иметь


единственный, авторитетный и непротиворечивый
источник в рамках системы

• Этот принцип включает в себя дублирование кода,


использование именованных констант вместо
литералов, но не ограничивается ими.
– Например, код, документация и диаграммы это три разных
представления модели. DRY требует, чтобы все три
представления имели один и тот же источник
Keep It Simple Stupid
(не усложняй)
• Архитектура системы должна быть максимально
простой

• Защита от желания разработчиков применить более


сложные конструкции, чем необходимо

• ВАЖНО: предполагается, что система работает и


остается объектно-ориентированной вне зависимости
от сложности архитектуры
You Ain’t Gonna Need It
(тебе это не понадобится)

• Не нужно реализовывать функциональность,


которая “понадобится в будущем”

• Защита от желания разработчиков реализовать


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

Доверяйте своей способности всё


исправить
S O L I D

ependency inversion
nterface segregation
iskov Substitution
pen / close
ingle Responsibility
Open-Close Principle
(принцип открыто-закрыто)

• Сущности (классы, модули, функции) должны


быть открыты для расширения и закрыты
для изменений.

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


добавлением новых сущностей, а не
изменением старых.
OCP
Single Responsibility Principle
(принцип единственности ответственности)

• Причина изменений в классе — его


ответственность.
Класс должен иметь лишь одну возможную
причину для изменений

• Класс должен решать одну хорошо


определенную задачу
SRP
“Бьорн — датский пекарь”
“Бьорн”
“Бьорн”
“Бьорн”
“Бьорн”
“Бьорн”
“Бьорн”
“Бьорн”
“Бьорн”
Interface Segregation Principle
(принцип разделения интерфейсов)

• Клиенты не должны зависеть от интерфейсов,


в которых не нуждаются.

• Лучше много «тонких» хорошо определенных


интерфейсов, нежели один «толстый»,
который отвечает за все
ISP: МФУ Xerox
ISP: МФУ Xerox
ISP: System.Collections.IList
ISP: System.Collections.Generic.IList
ISP
Dependency Inversion Principle
(принцип инверсии зависимости)

• Классы верхних уровней не должны зависеть от


классов нижних уровней.
Оба типа классов должны зависеть от
интерфейсов.

• Абстракции не должны зависеть от деталей.


Детали должны зависеть от абстракций
DIP: Векторная графика

?
DIP: Векторная графика
Liskov Substitution Principle
(Принцип подстановки Лисков)
• Объект базового типа можно заменить объектом
производного типа без ущерба для
правильности работы программы
• Наследуемый класс не может иметь более
сильных пред-условий или более слабых пост-
условий.
• Наследуемый класс не может
– Требовать большего
– Обещать меньшее
LSP: Прямоугольник и квадрат
LSP: Прямоугольник и квадрат
LSP: System.Collections.IList
Спасибо за внимание.
Вопросы?

Оценить