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

Паттерн 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();
    }
}
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 — поведенческий паттерн, который помогает упростить взаимодействие между объектами, превращая множество связей «всё со всеми» в одну централизованную связь через посредника. Он особенно полезен в графических интерфейсах, чатах, игровых системах и сложных модулях взаимодействия.