Předpoklady
Tutoriál očekává od čtenáře základní znalosti jazyka C# a objektově orientovaného programování.
Kde se tu vzal a co tu chce?
Návrhový vzor Mediator byl poprvé oficiálně představen v knize Design Patterns: Elements of Reusable Object-Oriented Software.
Upřímně jsem tuto knihu nikdy nečetl, jelikož internet je plný výtažků z této knihy a nejsem fanouškem učení se z knih.
Mediator zapouzdřuje vzájemnou interakci a komunikaci objektů. Jedná se o návrhový vzor podporující snížení referencí objektů a vyhnutí se složitého grafu závislostí.
Složitý graf závislostí je něco, čemu se snažíme jako programátoři vyhnout a návrhový vzor Mediator je konkrétní implementace jak tomu předejít. Mediator umožňuje objektům vyhnout se přímé závislosti na sobě a zapouzdřuje komunikaci jako centrální komunikační objekt.
Pro komunikaci si vytvoříme centrální objekt Mediator. Tento jediný objekt bude mít veškerou zodpovědnost za udržování referencí na objekty v našem projektu. Bude také zodpovědný za předávání veškerých zpráv či komunikaci mezi a k objektům. Můžete si ho představit jako komunikační uzel.
Vztah mezi komponentami
Mediator se obecně dělí na čtyři komponenty:
- Mediator —Definuje komunikaci mezi objekty Colleague.
- Concrete Mediator — Implementuje komunikaci mezi objekty Colleague.
- Colleague —Komunikuje pouze s Mediatorem.
- Concrete Colleague — Přijímá zprávy od Mediatoru.
Mediator je běžné definován jako abstraktní třída. Colleague je také abstraktní třída, ale zato reprezentuje příbuznou kolekci objektů. Je závislá pouze na Mediatoru a komunikuje pouze s ním. Vztah mezi abstraktními třídami je obousměrný.
Concrete Mediator dědí z abstraktního Mediatoru a implementuje komunikaci, která byla definována abstraktní metodou Send v Mediatoru bázovém.
Concrete Colleague je jednoduše řečeno různý typ potomků, který dědí z bázové třídy Colleage a definuje specifické chování.
Implementace
Pojďme implementovat náš první Mediator. Nejprve potřebujeme vytvořit abstraktní třídu s názvem Mediator a definici abstraktní metody Send.
public abstract class Mediator
{
public abstract void Send(string message, Colleague colleague);
}
Poté vytvoříme abstraktní třídu Colleague.
public abstract class Colleague
{
protected Mediator _mediator;
protected Colleague(Mediator mediator){
_mediator = mediator;
}
public void Send(string message){
_mediator.Send(message, this);
}
public abstract void HandleNotification(string message);
}
Jak můžete vidět, přidal jsem trochu více kódu, který záhy vysvětlím.
Nejprve jsem přidal konstruktor, který přijímá parametr Mediator a ukládá ho do dědičné třídní proměnné.
Poté jsem implementoval metodu Send, která bude zasílat zprávy skrze Mediator, který je uložen v třídní proměnné.
A nakonec ještě definuji abstraktní metodu HandleNotification. Tato metoda slouží jako předpis místa, kde budeme přijímat zprávy.
Nyní pojďme přidat třídy reprezentující komponentu Concrete Colleague. Implementujeme je tak, aby dědily z abstraktní bázové třídy Colleague.
public class Colleague1 : Colleague
{
public Colleague1(Mediator mediator) : base(mediator) { }
public override void HandleNotification(string message){
Console.WriteLine($"Colleague1 receives message:{message}");
}
}
public class Colleague2 : Colleague
{
public Colleague1(Mediator mediator) : base(mediator) { }
public override void HandleNotification(string message){
Console.WriteLine($"Colleague2 receives message:{message}");
}
}
Pokud dědíme z třídy Colleague, musíme implementovat tělo předepsané abstraktní třídy HandleNotification. Implementace je jednoduchý informativní zápis do konzole o tom, že zpráva dorazila v pořádku.
Ještě potřebujeme vytvořit poslední třídu, která bude reprezentovat komponentu Concrete Mediator a tak ji i nazveme.
public class ConcreteMediator : Mediator
{
public Colleague1 Colleague1 { get; set; }
public Colleague2 Colleague2 { get; set; }
public override void Send(string message, Colleague colleague){
if(colleague == Colleague1){
Colleague2.HandleNotification(message);
}
else{
Colleague1.HandleNotification(message);
}
}
}
Podívejte se na metodu Send. V ní vidíte implementaci funkce pro kterou nám byl návrhový vzor vytvořen, a to zajištění komunikace mezi objekty. V této konkrétní situaci zasílám zprávy objektu Colleague1 do objektu Colleague2 a naopak.
Dost bylo definování tříd. Nyní pojďme implementovat program, který Mediator využije.
class Program
{
static void Main(string[] args){
var mediator = new ConcreteMediator();
var c1 = new Colleague1(mediator);
var c2 = new Colleague2(mediator);
mediator.Colleague1 = c1;
mediator.Colleague2 = c2;
c1.Send("Hello, World! (from c1)");
c2.Send("Hello, World! (from c2)");
}
}
V programu jsem vytvořil objekt typu ConcreteMediator a následně objekty typu Colleague1 a Colleague2. Všimněte si, že oběma předávám objekt Mediator jako parametr jejich konstruktoru.
Poté informujeme Mediator předáním referencí na objekty c1 a c2 do předem připravených Properties. Tím jsme zajistili obousměrnou komunikaci a jsme připraveni k zasílání zpráv.
Po spuštění programu můžeme vidět výpis v konzoli, kde se můžete přesvědčit, že zprávy dorazily v pořádku.
Výhody použití Mediatoru
Mediator si můžete představit jako komunikační uzel. Stará se o správný směr zasílání zpráv za vás. Taková zpráva nemusí být pouze řetězcového typu.
Benefitem je také schopnost zapouzdřovat interakci mezi objekty tak, aby objekty o sobě nemusely vůbec vědět.
Návrhové vzory jsou pouze jedna z možností, jak řešit obecné problémy. Nejedná se o nařízení vrytá do kamene. Existuje mnoho různých implementací. Tímto velmi jednoduchým tutoriálem jsem vám chtěl nastínit, jak by mohla implementace vypadat.





