Посредник (шаблон проектирования)
Посредник (англ. Mediator) — поведенческий шаблон проектирования, обеспечивающий взаимодействие множества объектов, формируя при этом слабое зацепление и избавляя объекты от необходимости явно ссылаться друг на друга.
Посредник | |
---|---|
Mediator | |
Тип | поведенческий |
Описан в Design Patterns | Да |
Проблема
Обеспечить взаимодействие множества объектов, сформировав при этом слабую связанность и избавив объекты от необходимости явно ссылаться друг на друга.
Решение
Создать объект, инкапсулирующий способ взаимодействия множества объектов.
Преимущества
Устраняется связанность между "Коллегами", централизуется управление.
Структура
- Mediator – "Посредник"
- ConcreteMediator – "Конкретный посредник"
- Классы Colleague – "Коллеги"
Описание
"Посредник" определяет интерфейс для обмена информацией с объектами "Коллеги", "Конкретный посредник" координирует действия объектов "Коллеги". Каждый класс "Коллеги" знает о своем объекте "Посредник", все "Коллеги" обмениваются информацией только с посредником, при его отсутствии им пришлось бы обмениваться информацией напрямую. "Коллеги" посылают запросы посреднику и получают запросы от него. "Посредник" реализует кооперативное поведение, пересылая каждый запрос одному или нескольким "Коллегам".
Примеры
Пример на PHP5
<?php
abstract class Mediator
{
abstract public function send($message, Colleague $colleague);
}
abstract class Colleague
{
protected $mediator;
public function __construct(Mediator $mediator)
{
$this->mediator = $mediator;
}
public function send($message)
{
$this->mediator->send($message, $this);
}
/**
* Обработка полученного сообщения реализуется каждым конкретным
* наследником
* @param string message получаемое сообщение
*/
abstract public function notify($message);
}
class ConcreteMediator extends Mediator
{
/**
* @var ConcreteColleague1
*/
private $colleague1;
/**
* @var ConcreteColleague2
*/
private $colleague2;
public function setColleague1(ConcreteColleague1 $colleague)
{
$this->colleague1 = $colleague;
}
public function setColleague2(ConcreteColleague2 $colleague)
{
$this->colleague2 = $colleague;
}
public function send($message, Colleague $colleague)
{
switch ($colleague) {
case $this->colleague1:
$this->colleague2->notify($message);
break;
case $this->colleague2:
$this->colleague1->notify($message);
}
}
}
//коллега 1
class ConcreteColleague1 extends Colleague
{
public function notify($message)
{
echo sprintf("Colleague1 gets message: %s\n", $message);
}
}
//коллега 2
class ConcreteColleague2 extends Colleague
{
public function notify($message)
{
echo sprintf("Colleague2 gets message: %s\n", $message);
}
}
$mediator = new ConcreteMediator();
$collegue1 = new ConcreteColleague1($mediator);
$collegue2 = new ConcreteColleague2($mediator);
$mediator->setColleague1($collegue1);
$mediator->setColleague2($collegue2);
$collegue1->send('How are you ?');
$collegue2->send('Fine, thanks!');
Пример на Java
public abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public void send(String message) {
mediator.send(message, this);
}
public abstract void notify(String message);
}
public abstract class Mediator {
public abstract void send(String message, Colleague sender);
}
public class ConcreteColleague1 extends Colleague {
public ConcreteColleague1(Mediator mediator) {
super(mediator);
}
@Override
public void notify(String message) {
System.out.println("Colleague1 gets message: " + message);
}
}
public class ConcreteColleague2 extends Colleague {
public ConcreteColleague2(Mediator mediator) {
super(mediator);
}
@Override
public void notify(String message) {
System.out.println("Colleague2 gets message: " + message);
}
}
public class ConcreteMediator extends Mediator {
private ConcreteColleague1 colleague1;
private ConcreteColleague2 colleague2;
public void setColleague1(ConcreteColleague1 colleague) {
this.colleague1 = colleague;
}
public void setColleague2(ConcreteColleague2 colleague) {
this.colleague2 = colleague;
}
@Override
public void send(String message, Colleague sender) {
if (sender.equals(colleague1)) {
colleague2.notify(message);
} else {
colleague1.notify(message);
}
}
}
public class Main {
public static void main(String[] args) {
ConcreteMediator m = new ConcreteMediator();
ConcreteColleague1 c1 = new ConcreteColleague1(m);
ConcreteColleague2 c2 = new ConcreteColleague2(m);
m.setColleague1(c1);
m.setColleague2(c2);
c1.send("How are you?");
c2.send("Fine, thanks");
}
}
Пример на C#
// Mediator pattern — Structural example
using System;
namespace DoFactory.GangOfFour.Mediator.Structural
{
/// <summary>
/// MainApp startup class for Structural
/// Mediator Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
ConcreteMediator m = new ConcreteMediator();
ConcreteColleague1 c1 = new ConcreteColleague1(m);
ConcreteColleague2 c2 = new ConcreteColleague2(m);
m.Colleague1 = c1;
m.Colleague2 = c2;
c1.Send("How are you?");
c2.Send("Fine, thanks");
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Mediator' abstract class
/// </summary>
abstract class Mediator
{
public abstract void Send(string message, Colleague colleague);
}
/// <summary>
/// The 'ConcreteMediator' class
/// </summary>
class ConcreteMediator : Mediator
{
public ConcreteColleague1 Colleague1 { private get; set; }
public ConcreteColleague2 Colleague2 { private get; set; }
public override void Send(string message, Colleague colleague)
{
if (colleague == Colleague1)
{
Colleague2.Notify(message);
}
else
{
Colleague1.Notify(message);
}
}
}
/// <summary>
/// The 'Colleague' abstract class
/// </summary>
abstract class Colleague
{
protected Mediator mediator;
// Constructor
public Colleague(Mediator mediator)
{
this.mediator = mediator;
}
}
/// <summary>
/// A 'ConcreteColleague' class
/// </summary>
class ConcreteColleague1 : Colleague
{
// Constructor
public ConcreteColleague1(Mediator mediator)
: base(mediator)
{
}
public void Send(string message)
{
mediator.Send(message, this);
}
public void Notify(string message)
{
Console.WriteLine("Colleague1 gets message: " + message);
}
}
/// <summary>
/// A 'ConcreteColleague' class
/// </summary>
class ConcreteColleague2 : Colleague
{
// Constructor
public ConcreteColleague2(Mediator mediator)
: base(mediator)
{
}
public void Send(string message)
{
mediator.Send(message, this);
}
public void Notify(string message)
{
Console.WriteLine("Colleague2 gets message: " + message);
}
}
}
Output
Colleague2 gets message: How are you?
Colleague1 gets message: Fine, thanks
Пример на C++
#include <iostream>
#include <string>
class Colleague;
class Mediator;
class ConcreteMediator;
class ConcreteColleague1;
class ConcreteColleague2;
class Mediator
{
public:
virtual void Send(std::string const& message, Colleague *colleague) const = 0;
};
class Colleague
{
protected:
Mediator* mediator_;
public:
explicit Colleague(Mediator *mediator):mediator_(mediator)
{
}
};
class ConcreteColleague1:public Colleague
{
public:
explicit ConcreteColleague1(Mediator* mediator):Colleague(mediator)
{
}
void Send(std::string const& message)
{
mediator_->Send(message, this);
}
void Notify(std::string const& message)
{
std::cout << "Colleague1 gets message '" << message << "'" << std::endl;
}
};
class ConcreteColleague2:public Colleague
{
public:
explicit ConcreteColleague2(Mediator *mediator):Colleague(mediator)
{
}
void Send(std::string const& message)
{
mediator_->Send(message, this);
}
void Notify(std::string const& message)
{
std::cout << "Colleague2 gets message '" << message << "'" << std::endl;
}
};
class ConcreteMediator:public Mediator
{
protected:
ConcreteColleague1 *m_Colleague1;
ConcreteColleague2 *m_Colleague2;
public:
void SetColleague1(ConcreteColleague1 *c)
{
m_Colleague1=c;
}
void SetColleague2(ConcreteColleague2 *c)
{
m_Colleague2=c;
}
virtual void Send(std::string const& message, Colleague *colleague) const
{
if (colleague==m_Colleague1)
{
m_Colleague2->Notify(message);
}
else if (colleague==m_Colleague2)
{
m_Colleague1->Notify(message);
}
}
};
int main()
{
ConcreteMediator m;
ConcreteColleague1 c1(&m);
ConcreteColleague2 c2(&m);
m.SetColleague1(&c1);
m.SetColleague2(&c2);
c1.Send("How are you?");
c2.Send("Fine, thanks");
std::cin.get();
return 0;
}
Output
Colleague2 gets message 'How are you?'
Colleague1 gets message 'Fine, thanks'
Пример на Python
from abc import ABCMeta, abstractmethod
from weakref import proxy
import inspect
class Mediator(metaclass=ABCMeta):
"""
Абстрактный канал общения между коллегами
"""
@abstractmethod
def send(self, message: str) -> None:
"""
Отправка сообщения между коллегами
"""
pass
class Colleague(metaclass=ABCMeta):
"""
Абстрактный работник, который не против пообщаться со своими коллегами
"""
def __init__(self, mediator: Mediator) -> None:
"""
Constructor.
:param mediator: канал общения с коллегами
"""
self._mediator = proxy(mediator)
@abstractmethod
def send(self, message: str) -> None:
"""
Отправка сообщения через канал общения
"""
pass
@abstractmethod
def receive(self, message: str) -> None:
"""
Получения сообщения через канал общения
"""
pass
class SkypeBetweenTwoColleagues(Mediator):
"""
Канал в скайпе для общения между двумя людьми
"""
def __init__(self) -> None:
"""
Constructor.
"""
self._first = None
self._second = None
def set_first(self, first: Colleague) -> None:
"""
Привязывает к каналу первого участника разговора
"""
self._first = first
def set_second(self, second: Colleague) -> None:
"""
Привязывает к каналу второго участника разговора
"""
self._second = second
def send(self, message: str) -> None:
sender = inspect.currentframe().f_back.f_locals['self']
receiver = self._first if sender == self._second else self._second
receiver.receive(message)
class Bill(Colleague):
def send(self, message: str) -> None:
self._mediator.send(message)
def receive(self, message: str) -> None:
print('Билл получил сообщение: {}'.format(message))
class Steve(Colleague):
def send(self, message: str) -> None:
self._mediator.send(message)
def receive(self, message: str) -> None:
print('Стив прочитал в скайпе сообщение: {}'.format(message))
if __name__ == '__main__':
print('OUTPUT:')
skype = SkypeBetweenTwoColleagues()
bill = Bill(skype)
steve = Steve(skype)
skype.set_first(bill)
skype.set_second(steve)
bill.send('Начинай работать, бездельник!')
steve.send('Нет')
'''
OUTPUT:
Стив прочитал в скайпе сообщение: Начинай работать, бездельник!
Билл получил сообщение: Нет
'''
Пример на Delphi
program MediatorExample;
{$APPTYPE CONSOLE}
type
IColleague = interface
procedure Send(AMessage: string);
procedure Notify(AMessage: string);
end;
TMediator = class
procedure Send(AMessage: string; ACollegue: IColleague); virtual; abstract;
end;
TConcreteMediator = class(TMediator)
public
FCollegue1: IColleague;
FCollegue2: IColleague;
procedure Send(AMessage: string; ACollegue: IColleague); override;
end;
TColleague = class(TInterfacedObject, IColleague)
public
FMediator: TMediator;
constructor Create(AMediator: TMediator);
procedure Send(AMessage: string); virtual; abstract;
procedure Notify(AMessage: string); virtual; abstract;
end;
ConcreteColleague1 = class(TColleague)
procedure Send(AMessage: string); override;
procedure Notify(AMessage: string); override;
end;
ConcreteColleague2 = class(TColleague)
procedure Send(AMessage: string); override;
procedure Notify(AMessage: string); override;
end;
{ TConcreteMediator }
procedure TConcreteMediator.Send(AMessage: string; ACollegue: IColleague);
begin
if ACollegue = FCollegue1 then
FCollegue2.Notify(AMessage)
else
FCollegue1.Notify(AMessage);
end;
{ TColleague }
constructor TColleague.Create(AMediator: TMediator);
begin
FMediator := AMediator;
end;
{ ConcreteColleague1 }
procedure ConcreteColleague1.Send(AMessage: string);
begin
FMediator.Send(AMessage, Self);
end;
procedure ConcreteColleague1.Notify(AMessage: string);
begin
Writeln('Colleague1 gets message: ' + AMessage);
end;
{ ConcreteColleague2 }
procedure ConcreteColleague2.Send(AMessage: string);
begin
FMediator.Send(AMessage, Self);
end;
procedure ConcreteColleague2.Notify(AMessage: string);
begin
Writeln('Colleague2 gets message: ' + AMessage);
end;
var
Mediator: TConcreteMediator;
Colleague1: ConcreteColleague1;
Colleague2: ConcreteColleague2;
begin
Mediator := TConcreteMediator.Create;
Colleague1 := ConcreteColleague1.Create(Mediator);
Colleague2 := ConcreteColleague2.Create(Mediator);
Mediator.FCollegue1 := Colleague1;
Mediator.FCollegue2 := Colleague2;
Colleague1.Send('How are you?');
Colleague2.Send('Fine, thanks');
Readln;
end.
Ссылки
- Паттерн Mediator (посредник) — назначение, описание, особенности и реализация на С++.
- Паттерны для масштабируемых JavaScript-приложений. Глава 10. Паттерн «Медиатор» — описание, пример реализации.