SOLID — это пять основных принципов объектно-ориентированного программирования, которые делают код более понятным, гибким и поддерживаемым. Разберем каждый принцип с реалистичными примерами на PHP.
Принцип единственной ответственности: Класс должен иметь только одну причину для изменения.
Нарушение принципа:
class Order {
public function calculateTotal() { /* ... */ }
public function saveToDatabase() { /* ... */ }
public function sendEmail() { /* ... */ }
}
Соблюдение принципа:
class Order {
public function calculateTotal() { /* ... */ }
}
class OrderRepository {
public function save(Order $order) { /* ... */ }
}
class OrderNotifier {
public function sendConfirmation(Order $order) { /* ... */ }
}
Принцип открытости/закрытости: Классы должны быть открыты для расширения, но закрыты для модификации.
Нарушение принципа:
class AreaCalculator {
public function calculate($shapes) {
foreach ($shapes as $shape) {
if ($shape instanceof Rectangle) {
$area += $shape->width * $shape->height;
} elseif ($shape instanceof Circle) {
$area += $shape->radius * $shape->radius * pi();
}
// Добавляем новые условия для новых фигур
}
}
}
Соблюдение принципа:
interface Shape {
public function area();
}
class Rectangle implements Shape {
public function area() {
return $this->width * $this->height;
}
}
class Circle implements Shape {
public function area() {
return $this->radius * $this->radius * pi();
}
}
class AreaCalculator {
public function calculate(Shape ...$shapes) {
foreach ($shapes as $shape) {
$area += $shape->area();
}
}
}
Принцип подстановки Барбары Лисков: Подклассы должны быть заменяемы на свои базовые классы.
Нарушение принципа:
class Bird {
public function fly() { /* ... */ }
}
class Penguin extends Bird {
public function fly() {
throw new Exception('Penguins cannot fly!');
}
}
Соблюдение принципа:
class Bird {
// Общие методы для всех птиц
}
class FlyingBird extends Bird {
public function fly() { /* ... */ }
}
class Penguin extends Bird {
// Пингвины не летают, но имеют другие методы
}
Принцип разделения интерфейсов: Клиенты не должны зависеть от методов, которые они не используют.
Нарушение принципа:
interface Worker {
public function work();
public function eat();
}
class HumanWorker implements Worker {
public function work() { /* ... */ }
public function eat() { /* ... */ }
}
class RobotWorker implements Worker {
public function work() { /* ... */ }
public function eat() { /* Не имеет смысла для робота */ }
}
Соблюдение принципа:
interface Workable {
public function work();
}
interface Eatable {
public function eat();
}
class HumanWorker implements Workable, Eatable {
public function work() { /* ... */ }
public function eat() { /* ... */ }
}
class RobotWorker implements Workable {
public function work() { /* ... */ }
}
Принцип инверсии зависимостей: Зависимости должны строиться на абстракциях, а не на конкретных реализациях.
Нарушение принципа:
class MySQLConnection {
public function connect() { /* ... */ }
}
class UserRepository {
private $connection;
public function __construct() {
$this->connection = new MySQLConnection();
}
}
Соблюдение принципа:
interface DatabaseConnection {
public function connect();
}
class MySQLConnection implements DatabaseConnection {
public function connect() { /* ... */ }
}
class UserRepository {
private $connection;
public function __construct(DatabaseConnection $connection) {
$this->connection = $connection;
}
}
interface PaymentMethod {
public function pay(float $amount): bool;
}
class CreditCardPayment implements PaymentMethod {
public function pay(float $amount): bool {
// Логика оплаты кредитной картой
return true;
}
}
class PayPalPayment implements PaymentMethod {
public function pay(float $amount): bool {
// Логика оплаты через PayPal
return true;
}
}
class PaymentProcessor {
private $paymentMethod;
public function __construct(PaymentMethod $paymentMethod) {
$this->paymentMethod = $paymentMethod;
}
public function process(float $amount): bool {
return $this->paymentMethod->pay($amount);
}
}
// Использование
$paymentMethod = new CreditCardPayment();
$processor = new PaymentProcessor($paymentMethod);
$processor->process(100.00);
Следование SOLID принципам делает код более: