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