Поведенческие паттерны проектирования в PHP
Поведенческие паттерны помогают наладить эффективное взаимодействие между объектами в системе.
1. Strategy (Стратегия)
Позволяет выбрать алгоритм выполнения задачи во время выполнения программы.
📌 Когда использовать? Если нужно переключаться между разными способами выполнения задачи.
Пример
interface PaymentStrategy {
public function pay(int $amount): string;
}
// Реализации стратегий
class PayPalPayment implements PaymentStrategy {
public function pay(int $amount): string {
return "Paid $amount via PayPal";
}
}
class CreditCardPayment implements PaymentStrategy {
public function pay(int $amount): string {
return "Paid $amount via Credit Card";
}
}
// Контекст, который использует стратегию
class PaymentContext {
private PaymentStrategy $strategy;
public function __construct(PaymentStrategy $strategy) {
$this->strategy = $strategy;
}
public function pay(int $amount): string {
return $this->strategy->pay($amount);
}
}
// Использование
$context = new PaymentContext(new PayPalPayment());
echo $context->pay(100); // "Paid 100 via PayPal"
$context = new PaymentContext(new CreditCardPayment());
echo $context->pay(200); // "Paid 200 via Credit Card"
2. Observer (Наблюдатель)
Позволяет объекту уведомлять других объектов о своем изменении.
📌 Когда использовать? Когда нужно автоматически обновлять несколько объектов при изменении одного.
Пример
interface Observer {
public function update(string $message): void;
}
class User implements Observer {
private string $name;
public function __construct(string $name) {
$this->name = $name;
}
public function update(string $message): void {
echo "$this->name received notification: $message\n";
}
}
class NewsChannel {
private array $subscribers = [];
public function subscribe(Observer $observer): void {
$this->subscribers[] = $observer;
}
public function notify(string $message): void {
foreach ($this->subscribers as $subscriber) {
$subscriber->update($message);
}
}
}
// Использование
$news = new NewsChannel();
$user1 = new User("Alice");
$user2 = new User("Bob");
$news->subscribe($user1);
$news->subscribe($user2);
$news->notify("Breaking News!");
// "Alice received notification: Breaking News!"
// "Bob received notification: Breaking News!"
3. Command (Команда)
Инкапсулирует запрос в объект, позволяя передавать его как параметр.
📌 Когда использовать? Когда нужно передавать запросы в виде объектов.
Пример
interface Command {
public function execute(): string;
}
class Light {
public function turnOn(): string {
return "Light is ON";
}
public function turnOff(): string {
return "Light is OFF";
}
}
class TurnOnLightCommand implements Command {
private Light $light;
public function __construct(Light $light) {
$this->light = $light;
}
public function execute(): string {
return $this->light->turnOn();
}
}
class RemoteControl {
private Command $command;
public function setCommand(Command $command): void {
$this->command = $command;
}
public function pressButton(): string {
return $this->command->execute();
}
}
// Использование
$light = new Light();
$turnOnCommand = new TurnOnLightCommand($light);
$remote = new RemoteControl();
$remote->setCommand($turnOnCommand);
echo $remote->pressButton(); // "Light is ON"
4. Chain of Responsibility (Цепочка обязанностей)
Передает запрос по цепочке обработчиков, пока кто-то не обработает его.
📌 Когда использовать? Когда нужно передавать запросы по цепочке обработчиков.
Пример
abstract class Handler {
private ?Handler $next = null;
public function setNext(Handler $handler): Handler {
$this->next = $handler;
return $handler;
}
public function handle(string $request): string {
if ($this->next) {
return $this->next->handle($request);
}
return "Request not handled";
}
}
class AuthHandler extends Handler {
public function handle(string $request): string {
if ($request === "auth") {
return "User authenticated";
}
return parent::handle($request);
}
}
class LoggingHandler extends Handler {
public function handle(string $request): string {
if ($request === "log") {
return "Logging request";
}
return parent::handle($request);
}
}
// Использование
$auth = new AuthHandler();
$log = new LoggingHandler();
$auth->setNext($log);
echo $auth->handle("auth"); // "User authenticated"
echo $auth->handle("log"); // "Logging request"
echo $auth->handle("other"); // "Request not handled"
5. State (Состояние)
Позволяет объекту менять свое поведение в зависимости от состояния.
📌 Когда использовать? Когда объект должен изменять свое поведение в зависимости от внутреннего состояния.
Пример
interface State {
public function handle(): string;
}
class HappyState implements State {
public function handle(): string {
return "I'm happy!";
}
}
class SadState implements State {
public function handle(): string {
return "I'm sad...";
}
}
class Person {
private State $state;
public function __construct(State $state) {
$this->state = $state;
}
public function setState(State $state): void {
$this->state = $state;
}
public function talk(): string {
return $this->state->handle();
}
}
// Использование
$person = new Person(new HappyState());
echo $person->talk(); // "I'm happy!"
$person->setState(new SadState());
echo $person->talk(); // "I'm sad..."
6. Mediator (Посредник)
Посредник управляет взаимодействием между объектами, уменьшая зависимость между ними.
📌 Когда использовать? Когда много объектов взаимодействуют между собой.
Пример
class ChatRoom {
public function showMessage(string $user, string $message): void {
echo "$user: $message\n";
}
}
class User {
private string $name;
private ChatRoom $chat;
public function __construct(string $name, ChatRoom $chat) {
$this->name = $name;
$this->chat = $chat;
}
public function send(string $message): void {
$this->chat->showMessage($this->name, $message);
}
}
// Использование
$chat = new ChatRoom();
$user1 = new User("Alice", $chat);
$user2 = new User("Bob", $chat);
$user1->send("Hello, Bob!"); // "Alice: Hello, Bob!"
$user2->send("Hi, Alice!"); // "Bob: Hi, Alice!"
Вывод
Паттерн | Когда использовать? |
Strategy | Если нужно переключаться между алгоритмами |
Observer | Если нужно уведомлять объекты об изменениях |
Command | Если нужно передавать запросы как объекты |
Chain of Responsibility | Если запрос должен пройти через несколько обработчиков |
State | Если объект должен менять поведение в зависимости от состояния |
Mediator | Если нужно управлять взаимодействием множества объектов |