Посредник(Mediator)

Что такое паттерн Посредник?

Паттерн Посредник (Mediator) — это поведенческий паттерн проектирования, который позволяет уменьшить взаимосвязь между множеством объектов, обеспечивая централизованное взаимодействие между ними. В этом паттерне объекты не взаимодействуют напрямую, а вместо этого все коммуникации проходят через посредника, который управляет взаимодействиями. Представьте, что у вас есть система чатов с несколькими пользователями. Вместо того чтобы каждый пользователь напрямую отправлял сообщения всем остальным, посредник (сервер чата) управляет всеми сообщениями. Пользователи отправляют сообщения посреднику, а он уже пересылает их нужным адресатам.

Зачем нужен паттерн Посредник?

Паттерн Посредник нужен для решения ряда проблем, связанных с взаимодействием между объектами в сложных системах. Он помогает упростить и централизовать управление коммуникациями, что делает систему более гибкой и поддерживаемой. Посредник позволяет собрать всю логику взаимодействий в одном месте. Это упрощает изменение и управление взаимодействиями, так как любые модификации нужно вносить только в код посредника, а не во все связанные объекты.

Когда следует использовать паттерн Посредник?

  1. Необходимо централизовать контроль за взаимодействиями: Когда требуется управлять всеми взаимодействиями из одного места для упрощения изменения и поддержки логики взаимодействий.
  2. Система становится сложной из-за множества прямых связей между объектами: Это может привести к тому, что объекты будут слишком сильно зависеть друг от друга, что усложнит поддержку и расширение системы.

Какие преимущества дает паттерн Посредник?

  1. Уменьшение связности: Снижается количество связей между объектами, делая систему более модульной и легкой для понимания.
  2. Централизация логики: Логика взаимодействий сосредоточена в одном месте, что упрощает управление и модификацию.
  3. Повышение гибкости: Легко добавлять или изменять взаимодействия без необходимости изменения кода объектов, участвующих во взаимодействиях.

Какие ключевые отличия от других поведенческих паттернов?

Цепочка обязанностей (Chain of Responsibility): Передает запрос последовательно по цепочке обработчиков, позволяя каждому обработчику либо обработать запрос, либо передать его дальше.
Команда (Command): Инкапсулирует запрос как объект, позволяя параметризовать клиентов с различными запросами, ставить запросы в очередь или протоколировать их выполнение.
Интерпретатор (Interpreter): Определяет грамматику языка и интерпретирует предложения на этом языке.
Итератор (Iterator): Предоставляет способ последовательного доступа к элементам агрегатного объекта без раскрытия его внутреннего представления.
Хранитель (Memento): Позволяет сохранять и восстанавливать внутреннее состояние объекта, не нарушая его инкапсуляцию.
Наблюдатель (Observer): Определяет зависимость типа "один ко многим" между объектами, при которой изменение состояния одного объекта ведет к оповещению и обновлению всех зависимых объектов.
Состояние (State): Позволяет объекту изменять свое поведение в зависимости от его состояния, создавая впечатление изменения его класса.
Стратегия (Strategy): Определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми, позволяя изменять алгоритм независимо от клиентов, которые его используют.
Шаблонный метод (Template Method): Определяет скелет алгоритма в методе, позволяя подклассам переопределять определенные шаги алгоритма без изменения его структуры.
Посетитель (Visitor): Представляет операцию, выполняемую над элементами объектной структуры, позволяя добавлять новые операции, не изменяя классы элементов.

UML-диаграмма

UML Diagram of Mediator Pattern
Клиент создает объект ConcreteMediator. Клиент создает объекты ConcreteColleague1 и ConcreteColleague2, передавая им объект ConcreteMediator. ConcreteMediator устанавливает ссылки на ConcreteColleague1 и ConcreteColleague2. ConcreteColleague1 отправляет сообщение через метод Send(string message). ConcreteMediator получает сообщение от ConcreteColleague1 через метод Send(string message, Colleague colleague). ConcreteMediator пересылает сообщение ConcreteColleague2 через метод Notify(string message). ConcreteColleague2 получает сообщение и выполняет необходимые действия.

Как работает паттерн Посредник?

Представьте себе авиадиспетчера в аэропорту. Самолеты не общаются напрямую друг с другом. Вместо этого они общаются с диспетчером, который координирует взлеты и посадки, чтобы избежать столкновений и обеспечить безопасное движение.
  1. Посредник — это отдельный объект, который управляет взаимодействием между другими объектами. Он знает обо всех участвующих объектах и координирует их действия.
  2. Объекты, которые должны взаимодействовать друг с другом, регистрируются у посредника. Они сообщают посреднику о своих действиях и состояниях, вместо того чтобы напрямую общаться друг с другом.
  3. Когда один объект хочет взаимодействовать с другим, он отправляет сообщение посреднику. Посредник принимает сообщение и решает, как и кому его передать. Это может включать вызов методов других объектов или выполнение каких-то действий.
  4. Посредник может также передавать обратную связь от одного объекта к другому, обеспечивая корректное выполнение взаимодействий.

Как реализовать паттерн на примере кода?

В примере игровой движок управляет взаимодействием между игроками и врагами. Когда один объект выполняет действие, это может повлиять на состояние других объектов.

1import java.util.ArrayList;
2import java.util.List;
3
4public class Program {
5    public static void main(String[] args) {
6        // Создаем игровой движок (медиатор)
7        IGameEngineMediator gameEngine = new GameEngine();
8
9        // Создаем игровые объекты
10        Player player1 = new Player("Player1", gameEngine);
11        Player player2 = new Player("Player2", gameEngine);
12        Enemy enemy1 = new Enemy("Enemy1", gameEngine);
13        Enemy enemy2 = new Enemy("Enemy2", gameEngine);
14
15        // Регистрируем игровые объекты в игровом движке
16        gameEngine.registerPlayer(player1);
17        gameEngine.registerPlayer(player2);
18        gameEngine.registerEnemy(enemy1);
19        gameEngine.registerEnemy(enemy2);
20
21        // Игроки и враги выполняют действия
22        player1.attack();
23        enemy1.attack();
24        player2.heal();
25    }
26}
27
28// Интерфейс медиатора (Mediator)
29// Определяет методы для регистрации игроков и врагов, а также для уведомления об событиях.
30interface IGameEngineMediator {
31    void registerPlayer(Player player);
32    void registerEnemy(Enemy enemy);
33    void notify(Object sender, String eventCode);
34}
35
36// Игровой движок (ConcreteMediator)
37// Реализует интерфейс медиатора и управляет взаимодействиями между игроками и врагами.
38class GameEngine implements IGameEngineMediator {
39    private final List<Player> players = new ArrayList<>();
40    private final List<Enemy> enemies = new ArrayList<>();
41
42    // Метод для регистрации игрока в игровом движке
43    @Override
44    public void registerPlayer(Player player) {
45        players.add(player);
46    }
47
48    // Метод для регистрации врага в игровом движке
49    @Override
50    public void registerEnemy(Enemy enemy) {
51        enemies.add(enemy);
52    }
53
54    // Метод для уведомления других объектов о событии
55    @Override
56    public void notify(Object sender, String eventCode) {
57        switch (eventCode) {
58            case "PlayerAttacked":
59                System.out.println("Игрок атакует врагов!");
60                for (Enemy enemy : enemies) {
61                    enemy.reactToAttack();
62                }
63                break;
64            case "EnemyAttacked":
65                System.out.println("Враг атакует игроков!");
66                for (Player player : players) {
67                    player.reactToAttack();
68                }
69                break;
70            case "PlayerHealed":
71                System.out.println("Игрок исцеляет игроков!");
72                for (Player player : players) {
73                    player.reactToHeal();
74                }
75                break;
76        }
77    }
78}
79
80// Абстрактный класс игрового объекта (Colleague)
81// Определяет базовые свойства и методы для игровых объектов.
82abstract class GameObject {
83    protected IGameEngineMediator gameEngine;
84    private final String name;
85
86    protected GameObject(String name, IGameEngineMediator gameEngine) {
87        this.name = name;
88        this.gameEngine = gameEngine;
89    }
90
91    public String getName() {
92        return name;
93    }
94}
95
96// Класс игрока (ConcreteColleague)
97// Реализует конкретного коллегу, представляющего игрока в игре.
98class Player extends GameObject {
99    public Player(String name, IGameEngineMediator gameEngine) {
100        super(name, gameEngine);
101    }
102
103    // Метод для атаки врага
104    public void attack() {
105        gameEngine.notify(this, "PlayerAttacked");
106    }
107
108    // Метод для исцеления другого игрока
109    public void heal() {
110        gameEngine.notify(this, "PlayerHealed");
111    }
112
113    // Реакция на атаку врага
114    public void reactToAttack() {
115        System.out.println(getName() + " готовится к защите!");
116    }
117
118    // Реакция на исцеление
119    public void reactToHeal() {
120        System.out.println(getName() + " чувствует себя лучше после исцеления!");
121    }
122}
123
124// Класс врага (ConcreteColleague)
125// Реализует конкретного коллегу, представляющего врага в игре.
126class Enemy extends GameObject {
127    public Enemy(String name, IGameEngineMediator gameEngine) {
128        super(name, gameEngine);
129    }
130
131    // Метод для атаки игрока
132    public void attack() {
133        gameEngine.notify(this, "EnemyAttacked");
134    }
135
136    // Реакция на атаку игрока
137    public void reactToAttack() {
138        System.out.println(getName() + " готовится к контратаке!");
139    }
140}
1from abc import ABC, abstractmethod
2
3# Интерфейс медиатора (Mediator)
4# Определяет методы для регистрации игроков и врагов, а также для уведомления об событиях.
5class IGameEngineMediator(ABC):
6    @abstractmethod
7    def register_player(self, player):
8        pass
9
10    @abstractmethod
11    def register_enemy(self, enemy):
12        pass
13
14    @abstractmethod
15    def notify(self, sender, event_code):
16        pass
17
18# Игровой движок (ConcreteMediator)
19# Реализует интерфейс медиатора и управляет взаимодействиями между игроками и врагами.
20class GameEngine(IGameEngineMediator):
21    def __init__(self):
22        self._players = []
23        self._enemies = []
24
25    # Метод для регистрации игрока в игровом движке
26    def register_player(self, player):
27        self._players.append(player)
28
29    # Метод для регистрации врага в игровом движке
30    def register_enemy(self, enemy):
31        self._enemies.append(enemy)
32
33    # Метод для уведомления других объектов о событии
34    def notify(self, sender, event_code):
35        if event_code == "PlayerAttacked":
36            print("Игрок атакует врагов!")
37            for enemy in self._enemies:
38                enemy.react_to_attack()
39        elif event_code == "EnemyAttacked":
40            print("Враг атакует игроков!")
41            for player in self._players:
42                player.react_to_attack()
43        elif event_code == "PlayerHealed":
44            print("Игрок исцеляет игроков!")
45            for player in self._players:
46                player.react_to_heal()
47
48# Абстрактный класс игрового объекта (Colleague)
49# Определяет базовые свойства и методы для игровых объектов.
50class GameObject(ABC):
51    def __init__(self, name, game_engine):
52        self.name = name
53        self._game_engine = game_engine
54
55# Класс игрока (ConcreteColleague)
56# Реализует конкретного коллегу, представляющего игрока в игре.
57class Player(GameObject):
58    def attack(self):
59        self._game_engine.notify(self, "PlayerAttacked")
60
61    def heal(self):
62        self._game_engine.notify(self, "PlayerHealed")
63
64    def react_to_attack(self):
65        print(f"{self.name} готовится к защите!")
66
67    def react_to_heal(self):
68        print(f"{self.name} чувствует себя лучше после исцеления!")
69
70# Класс врага (ConcreteColleague)
71# Реализует конкретного коллегу, представляющего врага в игре.
72class Enemy(GameObject):
73    def attack(self):
74        self._game_engine.notify(self, "EnemyAttacked")
75
76    def react_to_attack(self):
77        print(f"{self.name} готовится к контратаке!")
78
79# Основной класс программы
80if __name__ == "__main__":
81    # Создаем игровой движок (медиатор)
82    game_engine = GameEngine()
83
84    # Создаем игровые объекты
85    player1 = Player("Player1", game_engine)
86    player2 = Player("Player2", game_engine)
87    enemy1 = Enemy("Enemy1", game_engine)
88    enemy2 = Enemy("Enemy2", game_engine)
89
90    # Регистрируем игровые объекты в игровом движке
91    game_engine.register_player(player1)
92    game_engine.register_player(player2)
93    game_engine.register_enemy(enemy1)
94    game_engine.register_enemy(enemy2)
95
96    # Игроки и враги выполняют действия
97    player1.attack()
98    enemy1.attack()
99    player2.heal()
1using System;
2using System.Collections.Generic;
3
4internal class Program
5{
6    static void Main(string[] args)
7    {
8        // Создаем игровой движок (медиатор)
9        IGameEngineMediator gameEngine = new GameEngine();
10
11        // Создаем игровые объекты
12        Player player1 = new("Player1", gameEngine);
13        Player player2 = new("Player2", gameEngine);
14        Enemy enemy1 = new("Enemy1", gameEngine);
15        Enemy enemy2 = new("Enemy2", gameEngine);
16
17        // Регистрируем игровые объекты в игровом движке
18        gameEngine.RegisterPlayer(player1);
19        gameEngine.RegisterPlayer(player2);
20        gameEngine.RegisterEnemy(enemy1);
21        gameEngine.RegisterEnemy(enemy2);
22
23        // Игроки и враги выполняют действия
24        player1.Attack();
25        enemy1.Attack();
26        player2.Heal();
27    }
28}
29
30// Интерфейс медиатора (Mediator)
31// Определяет методы для регистрации игроков и врагов, а также для уведомления об событиях.
32public interface IGameEngineMediator
33{
34    void RegisterPlayer(Player player);
35    void RegisterEnemy(Enemy enemy);
36    void Notify(object sender, string eventCode);
37}
38
39// Игровой движок (ConcreteMediator)
40// Реализует интерфейс медиатора и управляет взаимодействиями между игроками и врагами.
41public class GameEngine : IGameEngineMediator
42{
43    private readonly List<Player> _players = new();
44    private readonly List<Enemy> _enemies = new();
45
46    // Метод для регистрации игрока в игровом движке
47    public void RegisterPlayer(Player player)
48    {
49        _players.Add(player);
50    }
51
52    // Метод для регистрации врага в игровом движке
53    public void RegisterEnemy(Enemy enemy)
54    {
55        _enemies.Add(enemy);
56    }
57
58    // Метод для уведомления других объектов о событии
59    public void Notify(object sender, string eventCode)
60    {
61        if (eventCode == "PlayerAttacked")
62        {
63            Console.WriteLine("Игрок атакует врагов!");
64            foreach (var enemy in _enemies)
65            {
66                enemy.ReactToAttack();
67            }
68        }
69        else if (eventCode == "EnemyAttacked")
70        {
71            Console.WriteLine("Враг атакует игроков!");
72            foreach (var player in _players)
73            {
74                player.ReactToAttack();
75            }
76        }
77        else if (eventCode == "PlayerHealed")
78        {
79            Console.WriteLine("Игрок исцеляет игроков!");
80            foreach (var player in _players)
81            {
82                player.ReactToHeal();
83            }
84        }
85    }
86}
87
88// Абстрактный класс игрового объекта (Colleague)
89// Определяет базовые свойства и методы для игровых объектов.
90public abstract class GameObject
91{
92    protected IGameEngineMediator _gameEngine;
93    public string Name { get; }
94
95    protected GameObject(string name, IGameEngineMediator gameEngine)
96    {
97        Name = name;
98        _gameEngine = gameEngine;
99    }
100}
101
102// Класс игрока (ConcreteColleague)
103// Реализует конкретного коллегу, представляющего игрока в игре.
104public class Player : GameObject
105{
106    public Player(string name, IGameEngineMediator gameEngine) : base(name, gameEngine) { }
107
108    // Метод для атаки врага
109    public void Attack()
110    {
111        _gameEngine.Notify(this, "PlayerAttacked");
112    }
113
114    // Метод для исцеления другого игрока
115    public void Heal()
116    {
117        _gameEngine.Notify(this, "PlayerHealed");
118    }
119
120    // Реакция на атаку врага
121    public void ReactToAttack()
122    {
123        Console.WriteLine($"{Name} готовится к защите!");
124    }
125
126    // Реакция на исцеление
127    public void ReactToHeal()
128    {
129        Console.WriteLine($"{Name} чувствует себя лучше после исцеления!");
130    }
131}
132
133// Класс врага (ConcreteColleague)
134// Реализует конкретного коллегу, представляющего врага в игре.
135public class Enemy : GameObject
136{
137    public Enemy(string name, IGameEngineMediator gameEngine) : base(name, gameEngine) { }
138
139    // Метод для атаки игрока
140    public void Attack()
141    {
142        _gameEngine.Notify(this, "EnemyAttacked");
143    }
144
145    // Реакция на атаку игрока
146    public void ReactToAttack()
147    {
148        Console.WriteLine($"{Name} готовится к контратаке!");
149    }
150}
1#include <iostream>
2#include <vector>
3#include <string>
4#include <memory>
5
6// Интерфейс медиатора (Mediator)
7class IGameEngineMediator {
8public:
9    virtual ~IGameEngineMediator() = default;
10    virtual void RegisterPlayer(class Player* player) = 0;
11    virtual void RegisterEnemy(class Enemy* enemy) = 0;
12    virtual void Notify(class GameObject* sender, const std::string& eventCode) = 0;
13};
14
15// Абстрактный класс игрового объекта (Colleague)
16// Определяет базовые свойства и методы для игровых объектов.
17class GameObject {
18public:
19    GameObject(std::string name, IGameEngineMediator* gameEngine)
20        : name_(std::move(name)), gameEngine_(gameEngine) {}
21
22    virtual ~GameObject() = default;
23
24    std::string GetName() const { return name_; }
25
26protected:
27    IGameEngineMediator* gameEngine_;
28    std::string name_;
29};
30
31// Класс игрока (ConcreteColleague)
32// Реализует конкретного коллегу, представляющего игрока в игре.
33class Player : public GameObject {
34public:
35    Player(std::string name, IGameEngineMediator* gameEngine)
36        : GameObject(std::move(name), gameEngine) {}
37
38    // Метод для атаки врага
39    void Attack() {
40        gameEngine_->Notify(this, "PlayerAttacked");
41    }
42
43    // Метод для исцеления другого игрока
44    void Heal() {
45        gameEngine_->Notify(this, "PlayerHealed");
46    }
47
48    // Реакция на атаку врага
49    void ReactToAttack() {
50        std::cout << name_ << " готовится к защите!\n";
51    }
52
53    // Реакция на исцеление
54    void ReactToHeal() {
55        std::cout << name_ << " чувствует себя лучше после исцеления!\n";
56    }
57};
58
59// Класс врага (ConcreteColleague)
60// Реализует конкретного коллегу, представляющего врага в игре.
61class Enemy : public GameObject {
62public:
63    Enemy(std::string name, IGameEngineMediator* gameEngine)
64        : GameObject(std::move(name), gameEngine) {}
65
66    // Метод для атаки игрока
67    void Attack() {
68        gameEngine_->Notify(this, "EnemyAttacked");
69    }
70
71    // Реакция на атаку игрока
72    void ReactToAttack() {
73        std::cout << name_ << " готовится к контратаке!\n";
74    }
75};
76
77// Игровой движок (ConcreteMediator)
78// Реализует интерфейс медиатора и управляет взаимодействиями между игроками и врагами.
79class GameEngine : public IGameEngineMediator {
80public:
81    void RegisterPlayer(Player* player) override {
82        players_.push_back(player);
83    }
84
85    void RegisterEnemy(Enemy* enemy) override {
86        enemies_.push_back(enemy);
87    }
88
89    void Notify(GameObject* sender, const std::string& eventCode) override {
90        if (eventCode == "PlayerAttacked") {
91            std::cout << "Игрок атакует врагов!\n";
92            for (auto enemy : enemies_) {
93                enemy->ReactToAttack();
94            }
95        } else if (eventCode == "EnemyAttacked") {
96            std::cout << "Враг атакует игроков!\n";
97            for (auto player : players_) {
98                player->ReactToAttack();
99            }
100        } else if (eventCode == "PlayerHealed") {
101            std::cout << "Игрок исцеляет игроков!\n";
102            for (auto player : players_) {
103                player->ReactToHeal();
104            }
105        }
106    }
107
108private:
109    std::vector<Player*> players_;
110    std::vector<Enemy*> enemies_;
111};
112
113int main() {
114    // Создаем игровой движок (медиатор)
115    GameEngine gameEngine;
116
117    // Создаем игровые объекты
118    Player player1("Player1", &gameEngine);
119    Player player2("Player2", &gameEngine);
120    Enemy enemy1("Enemy1", &gameEngine);
121    Enemy enemy2("Enemy2", &gameEngine);
122
123    // Регистрируем игровые объекты в игровом движке
124    gameEngine.RegisterPlayer(&player1);
125    gameEngine.RegisterPlayer(&player2);
126    gameEngine.RegisterEnemy(&enemy1);
127    gameEngine.RegisterEnemy(&enemy2);
128
129    // Игроки и враги выполняют действия
130    player1.Attack();
131    enemy1.Attack();
132    player2.Heal();
133
134    return 0;
135}
1<?php
2
3// Основной класс программы
4function main(): void
5{
6    // Создаем игровой движок (медиатор)
7    $gameEngine = new GameEngine();
8
9    // Создаем игровые объекты
10    $player1 = new Player("Player1", $gameEngine);
11    $player2 = new Player("Player2", $gameEngine);
12    $enemy1 = new Enemy("Enemy1", $gameEngine);
13    $enemy2 = new Enemy("Enemy2", $gameEngine);
14
15    // Регистрируем игровые объекты в игровом движке
16    $gameEngine->registerPlayer($player1);
17    $gameEngine->registerPlayer($player2);
18    $gameEngine->registerEnemy($enemy1);
19    $gameEngine->registerEnemy($enemy2);
20
21    // Игроки и враги выполняют действия
22    $player1->attack();
23    $enemy1->attack();
24    $player2->heal();
25}
26
27// Интерфейс медиатора (Mediator)
28// Определяет методы для регистрации игроков и врагов, а также для уведомления об событиях.
29interface IGameEngineMediator
30{
31    public function registerPlayer(Player $player): void;
32    public function registerEnemy(Enemy $enemy): void;
33    public function notify(object $sender, string $eventCode): void;
34}
35
36// Игровой движок (ConcreteMediator)
37// Реализует интерфейс медиатора и управляет взаимодействиями между игроками и врагами.
38class GameEngine implements IGameEngineMediator
39{
40    private array $players = [];
41    private array $enemies = [];
42
43    // Метод для регистрации игрока в игровом движке
44    public function registerPlayer(Player $player): void
45    {
46        $this->players[] = $player;
47    }
48
49    // Метод для регистрации врага в игровом движке
50    public function registerEnemy(Enemy $enemy): void
51    {
52        $this->enemies[] = $enemy;
53    }
54
55    // Метод для уведомления других объектов о событии
56    public function notify(object $sender, string $eventCode): void
57    {
58        if ($eventCode === 'PlayerAttacked') {
59            echo "Игрок атакует врагов!" . PHP_EOL;
60            foreach ($this->enemies as $enemy) {
61                $enemy->reactToAttack();
62            }
63        } elseif ($eventCode === 'EnemyAttacked') {
64            echo "Враг атакует игроков!" . PHP_EOL;
65            foreach ($this->players as $player) {
66                $player->reactToAttack();
67            }
68        } elseif ($eventCode === 'PlayerHealed') {
69            echo "Игрок исцеляет игроков!" . PHP_EOL;
70            foreach ($this->players as $player) {
71                $player->reactToHeal();
72            }
73        }
74    }
75}
76
77// Абстрактный класс игрового объекта (Colleague)
78// Определяет базовые свойства и методы для игровых объектов.
79abstract class GameObject
80{
81    protected IGameEngineMediator $gameEngine;
82    public string $name;
83
84    protected function __construct(string $name, IGameEngineMediator $gameEngine)
85    {
86        $this->name = $name;
87        $this->gameEngine = $gameEngine;
88    }
89}
90
91// Класс игрока (ConcreteColleague)
92// Реализует конкретного коллегу, представляющего игрока в игре.
93class Player extends GameObject
94{
95    public function __construct(string $name, IGameEngineMediator $gameEngine)
96    {
97        parent::__construct($name, $gameEngine);
98    }
99
100    // Метод для атаки врага
101    public function attack(): void
102    {
103        $this->gameEngine->notify($this, 'PlayerAttacked');
104    }
105
106    // Метод для исцеления другого игрока
107    public function heal(): void
108    {
109        $this->gameEngine->notify($this, 'PlayerHealed');
110    }
111
112    // Реакция на атаку врага
113    public function reactToAttack(): void
114    {
115        echo "{$this->name} готовится к защите!" . PHP_EOL;
116    }
117
118    // Реакция на исцеление
119    public function reactToHeal(): void
120    {
121        echo "{$this->name} чувствует себя лучше после исцеления!" . PHP_EOL;
122    }
123}
124
125// Класс врага (ConcreteColleague)
126// Реализует конкретного коллегу, представляющего врага в игре.
127class Enemy extends GameObject
128{
129    public function __construct(string $name, IGameEngineMediator $gameEngine)
130    {
131        parent::__construct($name, $gameEngine);
132    }
133
134    // Метод для атаки игрока
135    public function attack(): void
136    {
137        $this->gameEngine->notify($this, 'EnemyAttacked');
138    }
139
140    // Реакция на атаку игрока
141    public function reactToAttack(): void
142    {
143        echo "{$this->name} готовится к контратаке!" . PHP_EOL;
144    }
145}
146
147// Запуск основного процесса
148main();
149
150?>
1package main
2
3import (
4	"fmt"
5)
6
7// Главная функция программы
8func main() {
9	// Создаем игровой движок (медиатор)
10	gameEngine := NewGameEngine()
11
12	// Создаем игровые объекты
13	player1 := NewPlayer("Player1", gameEngine)
14	player2 := NewPlayer("Player2", gameEngine)
15	enemy1 := NewEnemy("Enemy1", gameEngine)
16	enemy2 := NewEnemy("Enemy2", gameEngine)
17
18	// Регистрируем игровые объекты в игровом движке
19	gameEngine.RegisterPlayer(player1)
20	gameEngine.RegisterPlayer(player2)
21	gameEngine.RegisterEnemy(enemy1)
22	gameEngine.RegisterEnemy(enemy2)
23
24	// Игроки и враги выполняют действия
25	player1.Attack()
26	enemy1.Attack()
27	player2.Heal()
28}
29
30// IGameEngineMediator представляет интерфейс медиатора (Mediator)
31// Определяет методы для регистрации игроков и врагов, а также для уведомления об событиях.
32type IGameEngineMediator interface {
33	RegisterPlayer(player *Player)
34	RegisterEnemy(enemy *Enemy)
35	Notify(sender interface{}, eventCode string)
36}
37
38// GameEngine представляет игровой движок (ConcreteMediator)
39// Реализует интерфейс медиатора и управляет взаимодействиями между игроками и врагами.
40type GameEngine struct {
41	players []*Player
42	enemies []*Enemy
43}
44
45// NewGameEngine создает новый экземпляр GameEngine
46func NewGameEngine() *GameEngine {
47	return &GameEngine{
48		players: []*Player{},
49		enemies: []*Enemy{},
50	}
51}
52
53// RegisterPlayer регистрирует игрока в игровом движке
54func (ge *GameEngine) RegisterPlayer(player *Player) {
55	ge.players = append(ge.players, player)
56}
57
58// RegisterEnemy регистрирует врага в игровом движке
59func (ge *GameEngine) RegisterEnemy(enemy *Enemy) {
60	ge.enemies = append(ge.enemies, enemy)
61}
62
63// Notify уведомляет других объектов о событии
64func (ge *GameEngine) Notify(sender interface{}, eventCode string) {
65	switch eventCode {
66	case "PlayerAttacked":
67		fmt.Println("Игрок атакует врагов!")
68		for _, enemy := range ge.enemies {
69			enemy.ReactToAttack()
70		}
71	case "EnemyAttacked":
72		fmt.Println("Враг атакует игроков!")
73		for _, player := range ge.players {
74			player.ReactToAttack()
75		}
76	case "PlayerHealed":
77		fmt.Println("Игрок исцеляет игроков!")
78		for _, player := range ge.players {
79			player.ReactToHeal()
80		}
81	}
82}
83
84// GameObject представляет абстрактный класс игрового объекта (Colleague)
85// Определяет базовые свойства и методы для игровых объектов.
86type GameObject struct {
87	name       string
88	gameEngine IGameEngineMediator
89}
90
91// NewGameObject создает новый экземпляр GameObject
92func NewGameObject(name string, gameEngine IGameEngineMediator) *GameObject {
93	return &GameObject{name: name, gameEngine: gameEngine}
94}
95
96// Player представляет класс игрока (ConcreteColleague)
97// Реализует конкретного коллегу, представляющего игрока в игре.
98type Player struct {
99	*GameObject
100}
101
102// NewPlayer создает новый экземпляр Player
103func NewPlayer(name string, gameEngine IGameEngineMediator) *Player {
104	return &Player{
105		GameObject: NewGameObject(name, gameEngine),
106	}
107}
108
109// Attack выполняет атаку врага
110func (p *Player) Attack() {
111	p.gameEngine.Notify(p, "PlayerAttacked")
112}
113
114// Heal выполняет исцеление другого игрока
115func (p *Player) Heal() {
116	p.gameEngine.Notify(p, "PlayerHealed")
117}
118
119// ReactToAttack реагирует на атаку врага
120func (p *Player) ReactToAttack() {
121	fmt.Printf("%s готовится к защите!\n", p.name)
122}
123
124// ReactToHeal реагирует на исцеление
125func (p *Player) ReactToHeal() {
126	fmt.Printf("%s чувствует себя лучше после исцеления!\n", p.name)
127}
128
129// Enemy представляет класс врага (ConcreteColleague)
130// Реализует конкретного коллегу, представляющего врага в игре.
131type Enemy struct {
132	*GameObject
133}
134
135// NewEnemy создает новый экземпляр Enemy
136func NewEnemy(name string, gameEngine IGameEngineMediator) *Enemy {
137	return &Enemy{
138		GameObject: NewGameObject(name, gameEngine),
139	}
140}
141
142// Attack выполняет атаку игрока
143func (e *Enemy) Attack() {
144	e.gameEngine.Notify(e, "EnemyAttacked")
145}
146
147// ReactToAttack реагирует на атаку игрока
148func (e *Enemy) ReactToAttack() {
149	fmt.Printf("%s готовится к контратаке!\n", e.name)
150}

Какие недостатки у паттерна Посредник?

  1. Единая точка отказа: Если посредник выйдет из строя, это может парализовать все взаимодействия в системе.
  2. Усложнение посредника: Посредник может стать очень сложным, если в системе много взаимодействий, что может привести к созданию "большого класса".

Когда не следует использовать паттерн Посредник?

  1. Низкая сложность взаимодействий: Если взаимодействия между объектами простые и их количество невелико, посредник может внести ненужную сложность в систему.
  2. Простые системы: Если система не имеет большого количества взаимодействий или если объекты могут легко взаимодействовать напрямую, использование посредника может быть излишним.

Какие альтернативы паттерну Посредник?

  1. Прямое взаимодействие: В простых системах объекты могут напрямую взаимодействовать друг с другом без использования посредника.
  2. Компоненты и события: В некоторых случаях использование событий и компонентного подхода может заменить посредника, особенно в графических интерфейсах и игровых движках.
  3. Сообщения и шины событий: Системы, основанные на событиях и сообщениях, могут использовать шины событий для управления взаимодействиями между компонентами.
  4. Паттерн Наблюдатель (Observer) : Используется для создания отношений "один ко многим", когда объекты уведомляют других об изменениях своего состояния.

Какие есть примеры взаимодействия с другими паттернами?

Команда (Command): Посредник может использовать команды для выполнения действий. Это позволяет разделить запросы и их обработку, делая систему более гибкой.
Наблюдатель (Observer): Посредник может уведомлять зарегистрированных наблюдателей о событиях, происходящих в системе, обеспечивая реакцию на изменения.
Стратегия (Strategy): Посредник может использовать стратегии для определения логики взаимодействий между объектами, выбирая подходящую стратегию в зависимости от контекста.

Какие реальные примеры использования паттерна Посредник?

  1. Игровые движки: В играх посредник может управлять взаимодействием между игровыми объектами, такими как персонажи, предметы и события.
  2. Чат-системы: В чат-приложениях посредник управляет отправкой и получением сообщений между пользователями, обеспечивая централизованное управление.
  3. Графические интерфейсы: В сложных GUI приложения посредник управляет взаимодействиями между кнопками, полями ввода и другими элементами интерфейса.
  4. Системы управления проектами: В системах управления проектами посредник координирует взаимодействие между различными модулями, такими как задачи, ресурсы и сроки.

Другие поведенческие паттерны


Попробуйте наш тренажер по паттернам!

Наш тренажер по паттернам проектирования, созданный на базе искусственного интеллекта, представляет собой уникальный инструмент для углубления ваших знаний и практических навыков. Этот тренажер разработан так, чтобы вы могли не просто изучать теорию, но и активно тренироваться в применении паттернов. Попробуйте тренажер бесплатно и оцените его преимущества. Наш инструмент поможет вам стать более уверенным в своих силах и овладеть важными навыками для успешной карьеры разработчика.

Тренажер