Fabryka obiektów

W poprzednim artykule opisałem, w jaki sposób wykorzystać wzorzec repozytorium w celu odseparowania kodu implementującego logikę biznesową od reprezentacji fizycznych źródeł danych. W przypadku rozszerzeń systemu Dynamics 365 Customer Engagement źródłem danych będzie oczywiście usługa OrganizationService opisana za pomocą interfejsu IOrganizationService. Do uniezależnienia kodu klienta (którym w naszym przypadku będzie klasa implementująca interfejs IPlugin) korzystającego z repozytoriów od ich faktycznej implementacji możemy wykorzystać wzorzec projektowy o nazwie „fabryka”. Jego zastosowanie pozwala na dużo łatwiejsze zarządzanie aplikacją, tworzenie łatwo testowalnego kodu oraz modyfikację klas repozytoriów bez wpływu na inne, zależne od nich klasy oraz na implementację samego klienta.

Poniższe przykłady pokazują, w jaki sposób możemy tworzyć obiekty, reprezentujące repozytoria danych, za pomocą fabryki obiektów. Analogiczne podejście możemy również zastosować do tworzenia klas zawierających implementację logiki biznesowej lub innych, wykorzystywanych przez .NET-owe rozszerzenia systemu Dynamics 365.

W artykule skorzystam z klasy PluginBase opisanej w tym miejscu. Dla uproszczenia w prezentowanych przykładach zostanie pominięta warstwa logiki biznesowej. Pobieranie danych odbywać się będzie bezpośrednio w klasach, które będą reprezentować rozszerzenia systemu Dynamics 365 oraz implementować interfejs IPlugin.

W najprostszym przypadku, chcąc uzyskać dostęp do danych z repozytorium z poziomu kodu tworzonego rozszerzenia, moglibyśmy napisać poniższy kod:

W powyższym przykładzie za tworzenie obiektu repozytorium odpowiada metoda Execute rozszerzenia, co jest ewidentnym przykładem zasady łamania rozdzielenia odpowiedzialności. Spróbujmy więc zbudować nową klasę, która będzie wykorzystywana przez kod pluginu do tworzenia nowych obiektów repozytorium.

Wykorzystanie powyższej klasy w metodzie Execute rozszerzenia systemu Dynamics 365 mogłoby wyglądać w następujący sposób:

W tym miejscu wielu z Was zakwestionuje zapewne przydatność powyższego przykładu. Faktycznie, udało nam się rozdzielić odpowiedzialność tworzenia obiektu od jego faktycznego wykorzystania. Jednak fabryka repozytoriów w prezentowanej postaci jest praktycznie zamknięta, jeżeli chodzi o możliwości rozbudowy. Próba rozszerzenia funkcjonalności klasy o możliwości tworzenia innych obiektów dziedziczących po RepositoryBase zakończyłaby się kodem złożonym z wielu wyrażeń warunkowych lub dodawaniem dedykowanych metod „Get” dla kolejnych klas reprezentujących repozytoria.

Problem ten możemy łatwo rozwiązać, wykorzystując typy generyczne. Przykładowa generyczna fabryka repozytoriów została przedstawiona poniżej:

Natomiast wykorzystanie powyższej fabryki z poziomu pluginów wygląda następująco:

Moim skromnym zdaniem powyższa implementacja posiada kilka niekorzystnych cech. Po pierwsze w celu utworzenia generycznego typu, korzystając z operatora new(), wprowadzony został bezargumentowy konstruktor. Po drugie, specjalnie na potrzeby tego przykładu do klasy bazowej RepositoryBase została dodana metoda „Initialize” pełniąca de facto rolę dodatkowego konstruktora. Wymusza to konieczność wprowadzenia dodatkowych sprawdzeń w kodzie oraz z moim przekonaniu wprowadza pewne dodatkowe, niepotrzebne zależności (nie mówiąc już o zgodności z wytycznymi „domain design”), których w tym przypadku łatwo moglibyśmy uniknąć. Na szczęście z pomocą przychodzi nam w tym przypadku klasa System.Activator. Przyjrzyjmy się, w jaki sposób możemy tworzyć obiekty bez szczegółowej wiedzy na temat ich klasy oraz korzystając z konstruktora przyjmującego IOrganizationService jako argument wejściowy.

Wybór sposobu implementacji fabryki obiektów w Waszych projektach pozostawiam czytelnikom. Daleki jestem w tym miejscu od stwierdzenia, że któraś z prezentowanych wersji jest lepsza od innych. Wybór powinien być uwarunkowany przyjętą architekturą rozwiązania, wymaganymi cechami generowanych obiektów, wygodą implementacji, a także zapewne osobistymi upodobaniami (w końcu nikt nie chce pracować z kodem, na który nie może patrzeć ;)).

Na koniec dodam, że to jeszcze nie wszystkie informacje na temat tworzenia i inicjalizacji obiektów w rozszerzeniach systemu Dynamics 365. W kolejnym rozdziale przyjrzymy się, w jaki sposób wykorzystać wzorzec wstrzykiwania zależności (dependecy injection) w przypadku trójwarstwowej architektury w pluginach oraz niestandardowych aktywnościach workflow.

Kod wykorzystany w tym rozdziale znajdziecie pod adresem: https://github.com/gashupl/dyn365devbestpractices/tree/master/XrmLabs.Blog.Dyn365BestPractices/Chapter03/Chapter03.Plugins

Total Views: 1624 ,
This Article Has 1 Comment
  1. Pingback: dotnetomaniak.pl

Comments are now closed.