Hlavní navigace

Složitý graf závislostí zjednodušen pomocí návrhového vzoru Mediator

22. 4. 2020
Doba čtení: 4 minuty

Sdílet

 Autor: Macrovector
Zjednodušte graf závislostí objektů pomocí návrhového vzoru Mediator. V českých luzích je také znám jako Prostředník. V jednoduchém tutoriálu si ukážeme, jak takový Mediator implementovat v jazyce C#.

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:

  1. Mediator  —Definuje komunikaci mezi objekty Colleague.
  2. Concrete Mediator  — Implementuje komunikaci mezi objekty Colleague.
  3. Colleague —Komunikuje pouze s Mediatorem.
  4. 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.

CS24_early

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.

Byl pro vás článek přínosný?

Autor článku

Pracuje jako softwarový vývojář sídlící v Českém Těšíně. Během kariéry prošel třemi IT firmami, zažil různé přístupy k vývoji a poznal různé technologie. Nyní pracuje pro společnost Itixo s.r.o., která má pobočky ve Frýdku-Místku a Ostravě.