Single responsibility (SRP) - принцип единой ответственности
- объект должен отвечать только за что-то одно и эта
ответственность должна быть инкапсулирована в класс.
Классы должны иметь одну и только одну причину для изменений.
Примеры использования SRP
- есть класс Order, в котором есть функционал отвечающий за работы с заказами и печать заказов. Следует разбить на 2 класса: Order и OrderPrint.
Когда стоит использовать SRP
- любое изменение логики поведения объекта приводит к изменениям в других местах приложения, где это не подразумевалось изначально
- невозможно легко отделить и применить класс в другой сфере приложения, так как это потянет ненужные зависимости
- объекту класса становится позволительно слишком много
Шаблоны использующий принципы SRP
- Разработка через тестирование
- Шаблон «Выделение класса»
- Шаблон «Фасад»
- Шаблон «Proxy»
- DAO
Open-Closed (OCP) - открытости и закрытости
- классы должны быть открыты для расширения (добавление нового поведения), и закрыты для изменения,
т.е при добавлении поведения класса, логика в нем не должна меняться.
Следует унаследовать от текущего класса или интерфейса и добавить функционал.
Примеры использования OCP
- имеется класс Logger, который пишет логи в файл. Требуется расширить функционал, что бы логи писались в БД. Правильной
реализацией будет создание общего интерфейса ILogger и наследование от него: FileLogger и DbLogger.
Liskov Substitution (LSP) - принцип подстановки
- при наследовании функционала класса, наследник должен дополнять поведение родителя, а не заменять его.
Если не удается добавить поведение без изменения базовой логики, то следует пересмотреть уровень абстрактности.
Interface Segregation (ISP) - разделение интерфейсов
- слишком «толстые» интерфейсы необходимо разделять на более маленькие,
чтобы наследники маленьких интерфейсов знали только о методах, которые необходимы им в работе
- классы которые реализуют интерфейс не должны зависеть от методов которых не реализуют
Dependency Inversion (DIP) - инверсия зависимости
- Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций.
- Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Примеры использования DIP
- имеется класс PasswordReminder который ожидает объект MySQLConnection. PasswordReminder - высокоуровневый класс,
а MySQLConnection - низкоуровневый. В случае изменения БД, потребуется изменение во многих местах в том числе и в PasswordReminder, что нарушает принцип открытости/закрытости.
Для соблюдение принципов, нужно MySQLConnection унаследовать от интерфейса IDbConnection, а в PasswordReminder ожидать экземпляр интерфейса IDbConnection вместо MySQLConnection.
interface IDbConnection {
public function connect();
}
class MySQLConnection implements IDbConnection {
public function connect() {
return "Database connection";
}
}
class PasswordReminder {
private $dbConnection;
public function __construct(IDbConnection $dbConnection) {
$this->dbConnection = $dbConnection;
}
}
Теперь оба модуля (низкоуровневый и высокоуровневый) зависят от абстракции.
Читайте также: Принципы программирования