...

Dlaczego warto i kiedy wykorzystać Mediator Pattern C#

Od kilku lat obserwujemy słuszny trend upraszczania aplikacji i sprawiania, aby interakcja użytkownika z nawet bardzo złożonymi systemami była możliwie płynna i jak najbardziej przejrzysta. Jednak, aby osiągnąć taką prostotę i wygodę w obszarze doświadczenia użytkownika, nierzadko zdarza się, że pod maską systemy obsługują dość złożone algorytmy przetwarzania i działają z wieloma różnymi interfejsami API. W tym artykule chciałbym podzielić się kilkoma pomysłami na to, jak za pomocą kilku trików programistycznych można uprościć kod zaplecza, czyniąc go bardziej zwięzłym, łatwiejszym w utrzymaniu i potencjalnie sprawiającym, że praca z nim będzie przyjemniejsza.

Czym jest wzorzec mediatora w języku C#? Definicja mediatora w języku C#

Czym jest Mediator Pattern w c# (mediator c# definicja)?. Wzorzec mediatora w C# to wzorzec projektowy używany głównie w celu zmniejszenia liczby bezpośrednich połączeń między klasami, co prowadzi do większej elastyczności i łatwiejszej konserwacji kodu. Jego głównym celem jest promowanie luźnego powiązania poprzez centralizację komunikacji zewnętrznej pomiędzy klasami w ramach jednego obiektu mediatora. Wzorzec ten zyskał popularność w latach 90., zwłaszcza wraz z wydaniem książki „Wzory projektowe” autorstwa Gang of Four. Jest to szczególnie przydatne w scenariuszach, w których komponenty systemu muszą współdziałać, ale bez wyraźnej wiedzy o sobie nawzajem, dzięki czemu system jest bardziej modułowy i łatwiejszy do refaktoryzacji lub rozbudowy.

Wzorzec Mediator c#: plusy i minusy

Wzorzec Mediator oferuje kilka korzyści, szczególnie w języku C#. Po pierwsze, promuje luźne powiązanie, zapewniając, że klasy nie komunikują się bezpośrednio, ale za pośrednictwem obiektu mediatora, co zwiększa łatwość konserwacji i możliwość ponownego użycia kodu. Centralizując logikę interakcji, zmiany we wzorcach komunikacji lub regułach biznesowych można ująć w mediatorze, utrzymując poszczególne komponenty w czystości i skupieniu. Co więcej, upraszcza protokoły obiektowe, wprowadzając mniej zależności między klasami. Wadą jest to, że źle zaprojektowany mediator może stać się klasą monolityczną, trudną w utrzymaniu, zwaną potocznie problemem „obiektu Boga”. Nadmierne poleganie na mediatorze może również prowadzić do zmniejszenia wydajności, jeśli zbyt wiele obiektów opóźnia swoje interakcje za jego pośrednictwem. Wreszcie dodanie nowej logiki może wymagać zmiany mediatora, a nie poszczególnych komponentów, co może stać się problematyczne w złożonych systemach.

Dlaczego warto używać mediator pattern?

Dlaczego warto używać mediator pattern w C#? Wzorzec Mediatora wyróżnia się jako rozwiązanie zapewniające wydajną i zorganizowaną komunikację pomiędzy wieloma klasami lub obiektami. Jedną z jego głównych korzyści jest redukcja skomplikowanych zależności między klasami, co z kolei promuje system łatwiejszy w utrzymaniu i oddzielony. Centralizując komunikację zewnętrzną w ramach pojedynczego obiektu mediatora, sprzyja to jasnemu podziałowi odpowiedzialności i zmniejsza ryzyko wystąpienia niezamierzonych skutków ubocznych w przypadku zmiany jednej klasy. Wzorzec oferuje również większą elastyczność w rozszerzaniu i modyfikowaniu systemów, ponieważ wprowadzanie nowych komponentów lub zmiana interakcji zazwyczaj wiąże się z aktualizacjami mediatora, a nie wielu pojedynczych klas. Co więcej, usprawniając interakcje poprzez wspólny interfejs, wzorzec Mediator może prowadzić do czystszej i bardziej spójnej bazy kodu, dzięki czemu system będzie łatwiejszy do zrozumienia i debugowania. Ogólnie rzecz biorąc, wykorzystanie wzorca Mediator może skutkować bardziej skalowalną, solidną i zwinną architekturą aplikacji.

Kiedy stosować Wzorzec Mediatora?

Jak stosować wzorzec mediatora? Kiedy używać mediator pattern w C#? mediator pattern jest szczególnie przydatny w sytuacjach, gdy system składa się z wielu klas lub obiektów, które wymagają interakcji, ale chcesz uniknąć ścisłego powiązania i skomplikowanych współzależności. Jest to dobry wybór, gdy zauważysz, że zmiana w jednej klasie wywołuje kaskadę zmian w kilku innych klasach. Ten wzorzec okazuje się korzystny w aplikacjach GUI, gdzie wiele komponentów musi współdziałać bez bezpośredniego połączenia. Jest to również istotne w przypadkach, gdy przewidujesz częste zmiany w interakcjach klas lub przy rozbudowie komponentów systemu. Stosowanie wzorca mediatora jest rozsądne, jeśli chcesz zamknąć logikę komunikacji w jednym miejscu, oferując scentralizowany punkt kontroli. Jednakże istotne jest wcześniejsze oszacowanie złożoności systemu, ponieważ wprowadzenie mediatora w zbyt prostych systemach może dodać niepotrzebne warstwy i złożoność.

Uproszczony przykład architektury systemu dla wzorca mediatora

Uproszczony przykład złożonego systemu może wyglądać podobnie do tego przedstawionego na poniższym schemacie. Istnieje urządzenie/robot, który jest w stanie przesyłać dane telemetryczne z informacją o jego stanie zdrowia, warunkach pracy czy otoczeniu. Z drugiej strony mamy aplikację użytkownika, dostarczającą najróżniejszych cennych informacji, potencjalnie pomagającą operatorowi urządzenia w zarządzaniu nim.

Diagram skupia się wyłącznie na pojedynczym przypadku użycia takiego systemu — żądaniu informacji o wybranym typie urządzenia.

Z punktu widzenia urządzenia mamy następujący przepływ:

  • Robot wysyła wiadomość telemetryczną
  • Za weryfikację tej wiadomości odpowiedzialny jest podmiot przetwarzający dane telemetryczne. Aby to zrobić, musi sprawdzić w Rejestrze typów urządzeń, czy odpowiedni typ istnieje.

Z punktu widzenia aplikacji mamy następujący przepływ:

  • aplikacja chce wyświetlić szczegóły wybranego typu urządzenia
  • aplikacja wysyła żądanie do rejestru typów urządzeń w celu uzyskania tych szczegółów

 

Wyzwania dla wzorca projektowego mediatora w języku C# w złożonych systemach

Jak to zwykle w takich systemach bywa, mamy wspólną funkcjonalność, dostępną dla różnych typów odbiorców za pośrednictwem najprawdopodobniej różnych środków transportu. Dodatkowo, podobnie jak na powyższym schemacie, w wielu przypadkach dostęp do poszczególnych funkcjonalności może wiązać się także z odmiennymi wymogami bezpieczeństwa. Ostatecznie jednak wynik wywołania zarówno wewnętrznego, jak i zewnętrznego interfejsu API trafia do tego samego magazynu danych, działa w ramach tej samej domeny typów urządzeń, wykorzystuje te same modele i możliwości filtrowania.

Simplifying system design with mediator pattern

Konfiguracja usługi w celu zorganizowania komunikacji według wzorca mediatora

Podejście do organizacji komunikacji w takim systemie mogłoby być następujące:

  • w przypadku wewnętrznego interfejsu API użyj komunikacji opartej na GRPC. Protokół GRPC staje się coraz bardziej popularny. Jego wydajność i niewielkie rozmiary sprawiają, że jest to doskonały wybór w przypadku komunikacji typu usługa-usługa.
  • w przypadku zewnętrznego interfejsu API należy powszechnie stosować komunikację opartą na technologii REST.

Oczywiście takie podejście wymaga osobnej infrastruktury i stosu komunikacyjnego. Jednocześnie jednak celem powinno być uczynienie tych warstw infrastruktury tak cienkimi, jak to możliwe, aby nie wyciekały żadne części logiki biznesowej do bitów komunikacyjnych, przy jednoczesnym zachowaniu kodu wolnego od duplikatów, modułowego i testowalnego.

Jednym z możliwych i całkiem fajnych rozwiązań byłoby tutaj użycie wzorca mediatora.
Wzorzec mediatora jest jednym z wzorców zachowań. W istocie pozwala programistom definiować, w jaki sposób różne obiekty oddziałują na siebie, bez wymogu bezpośredniego odwoływania się tych obiektów do siebie. Takie podejście pozwala na bardziej luźno powiązaną architekturę, niezależny rozwój poszczególnych klas i całkiem przydatną możliwość ponownego użycia komponentów.

Kluczowe aspekty podejścia sugerowanego na powyższym schemacie to:

  1. Wykorzystanie warstwy infrastruktury specyficznej dla interfejsu API. Może to być konfiguracja interfejsu API sieci Web platformy ASP.NET Core z oprogramowaniem pośredniczącym i kilkoma klasami kontrolerów. Może to być również plik GRPC „.proto” i automatycznie wygenerowane klasy usług.
  2. Opcjonalne użycie komponentu mapowania odpowiedzi specyficznego dla interfejsu API. Może to być pomocne, gdy istnieje potrzeba dostosowania niektórych części odpowiedzi specyficznych dla protokołu (np. kodów stanu odpowiedzi http). Taka warstwa w bardzo uproszczony sposób może mieć także zastosowanie do mapowania treści odpowiedzi, gdy istnieje wymóg, aby dane API nie eksponowało wszystkich części modelu, co może wynikać z wykonania Request Handlera.
  3. Korzystanie z mediatora i osoby zajmującej się wnioskami. Procedura obsługi jest tu właściwie kluczową częścią prezentowanego podejścia. Tutaj przechowywana jest cała logika biznesowa. Jest niezależny od infrastruktury lub frameworka, nadaje się do wielokrotnego użytku, można go testować i jest łatwy w utrzymaniu.

 

Przykład kodu wzorca mediatora w C#

Mediator pattern, przykład wzorca mediatora: aby wprowadzić przedstawione podejście do kodu, potrzeba tak naprawdę kilku komponentów.

Przykład kodu znajdziesz tu.

Warto tu zwrócić uwagę na kilka rzeczy:

  • Przykłady są napisane w języku C#. Korzystają z narzędzi i pakietów dostępnych w ekosystemie .NET. Jednak przy dzisiejszym bogactwie technologii i narzędzi jestem pewien, że podobne podejście byłoby równie łatwe do wdrożenia przy użyciu zupełnie innego stosu technologii.
  • Ważną częścią tej implementacji jest wykorzystanie komponentów dostępnych w fantastycznej bibliotece MediatR Jimmy’ego Bogarda. Jest to implementacja wspomnianego wzorca mediatora i istotna część całego rozwiązania, która spaja ze sobą wszystkie elementy.
  • Klasa kontrolera i klasa usługi GRPC mają jedną zależność od interfejsu IMediator i ta część nie powinna się zmieniać po pojawieniu się nowych wymagań. Implementacja, powiedzmy, funkcjonalności aktualizacji typu urządzenia wymagałaby zdefiniowania odpowiednich modeli żądań/odpowiedzi, procedury obsługi i jeszcze jednej metody podobnej do istniejącej Get w kontrolerze i/lub usłudze GRPC.
  • Rzeczywista procedura pobierania danych jest zawarta w procedurze obsługi, która zawiera wszystkie niezbędne zależności. Ponadto, jeśli z biegiem czasu ta konkretna procedura ulegnie zmianie, wystarczy wprowadzić zmiany tylko w tej jednej klasie.

 

Podsumowanie wzorca mediatora implementacji

Tego rodzaju podejście do organizacji kodu może nagrodzić programistów wieloma korzyściami. Jeśli chodzi o projekty na dużą skalę, zbudowane w oparciu o różne orkiestratory mikrousług z najróżniejszymi interfejsami API, zastosowanie podejścia podobnego do przedstawionego pozwoliło mi i moim kolegom z zespołu nie utonąć w zalewie interfejsów, tonie metod publicznych i prywatnych i stale aktualizowane sygnatury metod. Dzięki fantastycznemu wsparciu stosu technologii, z którego korzystaliśmy, w większości przypadków mogliśmy naprawdę skupić się na rzeczywistych wymaganiach biznesowych.

Można oczywiście powiedzieć, że zamiast walczyć z przytłaczającą liczbą interfejsów specyficznych dla usług, otrzymaliśmy niezliczoną ilość małych klas o jednym przeznaczeniu. To rzeczywiście prawda i rozwiązaniem jest oczywiście odpowiednie nazewnictwo komponentów. To jednak, jak niektórzy mogą wiedzieć, jest jedną z dwóch najtrudniejszych rzeczy w programowaniu i prawdopodobnie tematem na zupełnie inną historię.

What is Mediator Pattern in C#?

Z końcem artykułu o zastosowaniu wzorca mediatora w C# i jego wpływie na usprawnienie architektury systemów, warto zauważyć, jak istotne jest posiadanie solidnego partnera technologicznego, który może pomóc zrealizować te zaawansowane koncepcje w praktyce. Nasz zespół ekspertów TTMS specjalizuje się w implementacji rozwiązań Microsoft Azure, które są kluczowe w migracji do chmury Azure, zarządzaniu danymi IoT, AI i uczeniu maszynowym, modernizacji aplikacji, usługach Kubernetes w Azure oraz tworzeniu niestandardowych aplikacji. Dzięki naszemu doświadczeniu i umiejętnościom, możemy przekształcić te teoretyczne koncepcje w efektywne, skalowalne i bezpieczne rozwiązania, które napędzają Twój biznes.

Jeśli szukasz wsparcia w wykorzystaniu chmury Azure do optymalizacji Twoich aplikacji i systemów, nasz zespół jest gotowy do podjęcia wyzwania. Zapraszamy do kontaktu z nami, aby dowiedzieć się więcej o tym, jak możemy pomóc Twojej organizacji wykorzystać pełny potencjał Microsoft Azure. Odwiedź naszą stronę TTMS Azure i dowiedz się więcej o naszych usługach.

Wiktor Janicki Roche Poland

Transition Technologies MS świadczy usługi informatyczne terminowo, o wysokiej jakości i zgodnie z podpisaną umową. Polecamy firmę TTMS jako godnego zaufania i rzetelnego dostawcę usług IT oraz partnera wdrożeniowego Salesforce.

Czytaj więcej
Julien Guillot Schneider Electric

TTMS od lat pomaga nam w zakresie konfiguracji i zarządzania urządzeniami zabezpieczającymi z wykorzystaniem różnych technologii. Ueługi świadczone przez TTMS są realizowane terminowo, i zgodnie z umową.

Czytaj więcej

Już dziś możemy pomóc Ci rosnąć

Porozmawiajmy, jak możemy wesprzeć Twój biznes

TTMC Contact person
Monika Radomska

Sales Manager