Mediator design pattern jest przykładem behawioralnego (czynnościowego) wzorca projektowego. Wzorzec ten zastosujemy w przypadku gdy w naszym systemie będziemy posiadali wiele komunikujących się ze sobą obiektów. Wraz z rozbudową systemu i rosnącą liczbą obiektów powiązania między nimi mogą zacząć być trudne do utrzymania. Do tego każda zmiana w interfejsach obiektów będzie pociągała za sobą zmiany w sposobie komunikacji. W takim przypadku dobrym rozwiązaniem może być zrezygnowanie z bezpośredniej komunikacji na rzecz jednego centralnego węzła komunikacyjnego – mediatora.
Czym jest mediator?
Mediator najczęściej jest zwykłym obiektem używanym jako centralny węzeł komunikacyjny pomiędzy rozproszonymi częściami naszego systemu. Można w uproszczeniu powiedzieć, iż „mediator wie o wszystkich a wszyscy wiedzą tylko o mediatorze„. Poszczególne obiekty są świadome tego jak mają komunikować się z mediatorem (znają jego interfejs). Nie wiedzą za to nic o innych obiektach w systemie. To mediator dokładnie wie jak obsłużyć routing i komunikację zdejmując tą odpowiedzialność z innych obiektów. Jedynie on musi znać interfejsy innych części aplikacji. Takie podejście do problemu może sprawić, iż nasz kod i zawarta w nim logika będzie dużo czytelniejsza, ale…

Posiadanie mediatora wiąże się z jednym dość istotnym problemem. Jeżeli mediator przestanie działać – przestanie działać także wszystko co z niego korzysta. Dlatego więc należy zawsze przyłożyć dużą wagę na odpowiednie testowanie oraz obsługę błędów w mediatorze.
Przykład
Myśląc o przykładzie systemu w którym mógłby wystąpić mediator i zarządzać komunikacją między obiektami pewnie wielu osobom do głowy przyjdą komunikatory (np. Slack, MS Teams, etc.). W praktyce w takiej aplikacji nie będziemy wysyłali wiadomości bezpośrednio do innych użytkowników. Wiadomość taka trafi do odpowiedniego mechanizmu (mediatora), który to dopiero będzie wiedział jak ją pokierować, aby trafiła do właściwego okna. Mam nadzieję, że poniższy przykład wraz z komentarzami pomoże w zrozumieniu idei wzorca mediatora.
// pojedyńczy użytkownik czatu // w momencie inicjalizowania nie wie on nic o innych użytkownikach class User { constructor(nick) { this.nick = nick; // identyfikuje go jedynie nick this.chatroom = null; // i może on dołączyć do jednego pokoju czatu } addToChatroom(chatroom) { // za pomocą tej metody może dołączyć do czatu this.chatroom = chatroom; } sendMessage(message, to) { // może wysłać wiadomość - trafi ona do mediatora // przypominajka - this będzie odnosiło się do konkretnej instancji Usera this.chatroom.send(message, this, to); } receive(message, from, type) { // może wyświetlić otrzymaną wiadomość oraz jej nadawcę // wiadomość otrzymamy od mediatora console.log( `[To ${this.nick}] New ${type} message from ${from.nick}: ${message}` ); } } // "Chatroom" to mediator w naszym systemie // o on będzie odbierał i wysyłał dalej wiadomości class Chatroom { constructor() { this.participants = {}; // mediator wie o wszystkich uczestnikach czatu } join(participant) { // dodajemy nowego użytkownika do listy wszystkuch użytkowników this.participants[participant.nick] = participant; // łączymy użytkownika z tym konkretnym mediatorem // dzięki temu użytkownik będzie mógł z niego korzystać participant.addToChatroom(this); } /* Mediator jest odpowiedzilany za prawidłowe rozsyłanie dalej wiadomości które otrzyma od użytkowników. Możemy dodać tutaj wiele funkcjonalności jak np. filtrowanie niecenzuralnych słów, szyfrowanie/deszyfrowanie, itd. */ send(message, from, to) { if (to) { // jeżeli sprecyzujemy odbiorcę, // mediator wyśle to jako wiadomość prywatną to.receive(message, from, "private"); } else { // w przeciwnym wypadku wiadomośc trafi na czat grupowy // tzn. zostanie wysłana do wszystkich for (const key in this.participants) { if (this.participants[key] !== from) { this.participants[key].receive(message, from, "public"); } } } } } // Tworzymy instancję naszego mediatora const chatroom = new Chatroom(); // Tworzymy uczestników czatu const jan = new User("Jan"); const kamil = new User("Kamil"); const aga = new User("Aga"); const pjtr = new User("pjtr"); // użytkownicy czatu dołączają do pokoju czatu chatroom.join(jan); chatroom.join(kamil); chatroom.join(aga); chatroom.join(pjtr); // i wysyłają na czacie wiadomości jan.sendMessage("Czy znacie jakieś fajne filmy?"); jan.sendMessage("Szukam czegoś na weekend"); // wiadomość grupowa kamil.sendMessage("Hej, prywatnie mogę Ci polecić La La Land", jan); aga.sendMessage("Sprzedam Opla!"); pjtr.sendMessage("Aga, chyba nie ten kanał...", aga); // wiadomość prywatna

Podsumowanie
Mediator design pattern nie jest może jakimś często używanym wzorcem projektowym w JavaScript. Jednak znajomość tego podejścia może niejednokrotnie pomóc nam rozwiązać problemy komunikacji pojawiające się w rozproszonych systemach.