Course program← Объектно ориентированное программирование
1История ООП
2Объект и Класс
3Базовые концепции ООП
4Принцип проектирования GRASP
5Принцип проектирования SOLID
6Паттерны GOF

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

This lesson is not translated yet – the Russian original is below.

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

Когда применять Mediator

  • Когда множество объектов тесно связаны между собой, и изменения в одном влияют на другие.
  • Когда нужно централизовать управление взаимодействием между компонентами (например, UI-контролами).
  • Когда требуется упростить поддержку и тестирование за счёт снижения количества связей между объектами.

PlantUML-диаграмма

UML диаграмма Mediator

// Интерфейс посредника
public interface IMediator
{
    void Notify(object sender, string ev);
}

// Базовый класс компонентов
public class Component
{
    protected IMediator _mediator;

    public Component(IMediator mediator = null)
    {
        _mediator = mediator;
    }

    public void SetMediator(IMediator mediator)
    {
        _mediator = mediator;
    }
}

// Конкретные компоненты
public class Button : Component
{
    public void Click()
    {
        Console.WriteLine("Кнопка нажата.");
        _mediator?.Notify(this, "Click");
    }
}

public class TextBox : Component
{
    public void Show() => Console.WriteLine("Текстовое поле отображено.");
    public void Hide() => Console.WriteLine("Текстовое поле скрыто.");
}

public class Label : Component
{
    public void UpdateText(string text)
    {
        Console.WriteLine($"Метка обновлена: {text}");
    }
}

// Конкретный посредник
public class DialogMediator : IMediator
{
    private Button _button;
    private TextBox _textBox;
    private Label _label;

    public DialogMediator(Button button, TextBox textBox, Label label)
    {
        _button = button;
        _textBox = textBox;
        _label = label;

        _button.SetMediator(this);
        _textBox.SetMediator(this);
        _label.SetMediator(this);
    }

    public void Notify(object sender, string ev)
    {
        if (sender is Button && ev == "Click")
        {
            Console.WriteLine("Посредник обработал событие Click.");
            _textBox.Show();
            _label.UpdateText("Введите данные...");
        }
    }
}

// Клиентский код
class Program
{
    static void Main()
    {
        var button = new Button();
        var textBox = new TextBox();
        var label = new Label();

        var mediator = new DialogMediator(button, textBox, label);

        button.Click();
    }
}
// Интерфейс посредника
class IMediator {
public:
    virtual void Notify(const std::string& sender, const std::string& event) = 0;
    virtual ~IMediator() = default;
};

class Component {
public:
    void SetMediator(IMediator* mediator) { mediator_ = mediator; }
    virtual ~Component() = default;

protected:
    IMediator* mediator_ = nullptr;
};

class Button : public Component {
public:
    void Click() {
        std::cout << "Кнопка нажата." << std::endl;
        if (mediator_) mediator_->Notify("button", "Click");
    }
};

class TextBox : public Component {
public:
    void Show() { std::cout << "Текстовое поле отображено." << std::endl; }
    void Hide() { std::cout << "Текстовое поле скрыто." << std::endl; }
};

class Label : public Component {
public:
    void UpdateText(const std::string& text) {
        std::cout << "Метка обновлена: " << text << std::endl;
    }
};

class DialogMediator : public IMediator {
public:
    DialogMediator(Button& button, TextBox& text_box, Label& label)
        : text_box_(text_box), label_(label) {
        button.SetMediator(this);
    }

    void Notify(const std::string& sender, const std::string& event) override {
        if (sender == "button" && event == "Click") {
            std::cout << "Посредник обработал событие Click." << std::endl;
            text_box_.Show();
            label_.UpdateText("Введите данные...");
        }
    }

private:
    TextBox& text_box_;
    Label& label_;
};
type Mediator interface {
	Notify(sender any, event string)
}

type Button struct {
	mediator Mediator
}

func (b *Button) SetMediator(m Mediator) { b.mediator = m }

func (b *Button) Click() {
	fmt.Println("Кнопка нажата.")
	if b.mediator != nil {
		b.mediator.Notify(b, "Click")
	}
}

type TextBox struct{}

func (TextBox) Show() { fmt.Println("Текстовое поле отображено.") }
func (TextBox) Hide() { fmt.Println("Текстовое поле скрыто.") }

type Label struct{}

func (Label) UpdateText(text string) { fmt.Printf("Метка обновлена: %s\n", text) }

type DialogMediator struct {
	button  *Button
	textBox TextBox
	label   Label
}

func NewDialogMediator(button *Button, textBox TextBox, label Label) *DialogMediator {
	m := &DialogMediator{button: button, textBox: textBox, label: label}
	button.SetMediator(m)
	return m
}

func (m *DialogMediator) Notify(sender any, event string) {
	if _, ok := sender.(*Button); ok && event == "Click" {
		fmt.Println("Посредник обработал событие Click.")
		m.textBox.Show()
		m.label.UpdateText("Введите данные...")
	}
}

func main() {
	button := &Button{}

	NewDialogMediator(button, TextBox{}, Label{})

	button.Click()
}
from typing import Any, Protocol

class Mediator(Protocol):
    def notify(self, sender: Any, event: str) -> None: ...

class Button:
    def __init__(self) -> None:
        self.mediator: Mediator | None = None

    def click(self) -> None:
        print("Кнопка нажата.")
        if self.mediator is not None:
            self.mediator.notify(self, "Click")

class TextBox:
    def show(self) -> None:
        print("Текстовое поле отображено.")

    def hide(self) -> None:
        print("Текстовое поле скрыто.")

class Label:
    def update_text(self, text: str) -> None:
        print(f"Метка обновлена: {text}")

class DialogMediator:
    def __init__(self, button: Button, text_box: TextBox, label: Label) -> None:
        self._button = button
        self._text_box = text_box
        self._label = label
        button.mediator = self

    def notify(self, sender: Any, event: str) -> None:
        if isinstance(sender, Button) and event == "Click":
            print("Посредник обработал событие Click.")
            self._text_box.show()
            self._label.update_text("Введите данные...")

button = Button()

DialogMediator(button, TextBox(), Label())

button.click()
interface Mediator {
    notify(sender: object, event: string): void;
}

class Button {
    private mediator: Mediator | null = null;

    setMediator(mediator: Mediator): void {
        this.mediator = mediator;
    }

    click(): void {
        console.log("Кнопка нажата.");
        this.mediator?.notify(this, "Click");
    }
}

class TextBox {
    show(): void {
        console.log("Текстовое поле отображено.");
    }

    hide(): void {
        console.log("Текстовое поле скрыто.");
    }
}

class Label {
    updateText(text: string): void {
        console.log(`Метка обновлена: ${text}`);
    }
}

class DialogMediator implements Mediator {
    constructor(
        private readonly button: Button,
        private readonly textBox: TextBox,
        private readonly label: Label,
    ) {
        button.setMediator(this);
    }

    notify(sender: object, event: string): void {
        if (sender instanceof Button && event === "Click") {
            console.log("Посредник обработал событие Click.");
            this.textBox.show();
            this.label.updateText("Введите данные...");
        }
    }
}

const button = new Button();

new DialogMediator(button, new TextBox(), new Label());

button.click();
interface Mediator {
    void notify(Object sender, String event);
}

class Button {
    private Mediator mediator;

    void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    void click() {
        System.out.println("Кнопка нажата.");
        if (mediator != null) {
            mediator.notify(this, "Click");
        }
    }
}

class TextBox {
    void show() {
        System.out.println("Текстовое поле отображено.");
    }

    void hide() {
        System.out.println("Текстовое поле скрыто.");
    }
}

class Label {
    void updateText(String text) {
        System.out.println("Метка обновлена: " + text);
    }
}

class DialogMediator implements Mediator {
    private final TextBox textBox;
    private final Label label;

    DialogMediator(Button button, TextBox textBox, Label label) {
        this.textBox = textBox;
        this.label = label;
        button.setMediator(this);
    }

    public void notify(Object sender, String event) {
        if (sender instanceof Button && event.equals("Click")) {
            System.out.println("Посредник обработал событие Click.");
            textBox.show();
            label.updateText("Введите данные...");
        }
    }
}

public class Program {
    public static void main(String[] args) {
        Button button = new Button();

        new DialogMediator(button, new TextBox(), new Label());

        button.click();
    }
}
fun interface Mediator {
    fun notify(sender: Any, event: String)
}

class Button {
    var mediator: Mediator? = null

    fun click() {
        println("Кнопка нажата.")
        mediator?.notify(this, "Click")
    }
}

class TextBox {
    fun show() = println("Текстовое поле отображено.")
    fun hide() = println("Текстовое поле скрыто.")
}

class Label {
    fun updateText(text: String) = println("Метка обновлена: $text")
}

class DialogMediator(button: Button, private val textBox: TextBox, private val label: Label) : Mediator {
    init {
        button.mediator = this
    }

    override fun notify(sender: Any, event: String) {
        if (sender is Button && event == "Click") {
            println("Посредник обработал событие Click.")
            textBox.show()
            label.updateText("Введите данные...")
        }
    }
}

fun main() {
    val button = Button()

    DialogMediator(button, TextBox(), Label())

    button.click()
}

Плюсы и минусы

Плюсы Минусы
Изолирует компоненты, уменьшая связанность между ними Посредник может стать слишком сложным при большом количестве логики
Упрощает добавление новых компонентов Может затруднить понимание цепочки событий
Централизует контроль и координацию поведения системы Возможна деградация производительности при сложных сценариях

Заключение

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