Lekcja 1.3: Separacja z użyciem Proxy

Forum

Separacja z użyciem Proxy

 

Pokazaliśmy, jak wstrzykiwanie zależności pozwala nam się uniezależnić od konkretnej implementacji komponentu. Teraz spróbujemy pójść dalej. Przejdźmy na poziom FakePaymentService i teraz zobaczmy, że na poziomie FakePaymentService oprócz tego, że realizujemy płatność jednocześnie mamy funkcjonalność taką typowo poboczną, związaną z logowaniem. Innymi przykładami takiej funkcjonalności może być np. obsługa transakcji, może to być jakiś kod związany z bezpieczeństwem, może to być cachowanie. Ewidentnie widać, że nie jest to typowa logika biznesowa, tylko coś co będzie nam zaśmiecało tę logikę biznesową, przeplatało się z nią w wielu miejscach na poziomie kodu i będzie powodowało, że ten kod będzie dużo bardziej skomplikowany, będzie dużo trudniejszy w zrozumieniu. Będzie też dużo trudniej zarządzać takim kodem. Przy okazji znowu łamiemy zasadę pojedynczej odpowiedzialności, bo tak jak mówiliśmy, powinniśmy się skupić na realizacji płatności, a nie na logowaniu. Co będzie, jeżeli za chwilę pojawi się wymaganie, że nasze logi mają trafiać do bazy, że chcemy je na przykład gdzieś wysyłać, być może na jakiś inny serwer. Czyli mówiąc krótko, znowu mamy problem, znowu musimy coś z tym zrobić i skoro ten kod powiązany z logowaniem jest niewłaściwy, to powinniśmy go po prostu stąd usunąć. Powinniśmy go przenieść w inne miejsce. W części teoretycznej wspominałem o wzorcu Proxy. To jest taki wzorzec, który pozwala na to, żeby można było wyprodukować pośrednika, taki obiekt zastępczy, który dla klienta będzie wyglądał dokładnie tak samo, jak nasz oryginalny obiekt, ale przy okazji będziemy w stanie po pierwsze delegować wykonanie tego właściwego zadania do oryginalnego obiektu, a z drugiej strony będziemy też w stanie opakować oryginalną logikę właśnie jakąś logiką dodatkową. To jest dla nas idealny przypadek. Za pomocą obiektu proxy możemy pozbyć się teraz tego kodu związanego z logowaniem, wyrzucić go do specjalnego obiektu pomocniczego, pośredniczącego i uzyskać z jednej strony dużo bardziej czysty kod na poziomie FakePaymentService, ale jednocześnie dać sobie furtkę na to, żeby w przyszłości bardzo łatwo zamienić czy dodać również logowanie, chociażby na poziomie bazy danych. Spróbujmy to zrealizować, dodamy nową klasę, którą nazwiemy sobie LoggingPaymentService, ona również będzie implementowała ten sam interfejs co nasza usługa, bo tak jak mówiliśmy, z punktu widzenia klienta, proxy powinien być przezroczysty, on powinien reprezentować czy powinien udostępniać dokładnie taki sam interfejs. Czyli to, co powinniśmy zrobić to po raz kolejny wprowadzić interfejs. Interfejs, który będzie określał czym tak naprawdę jest usługa PaymentService. Jaki jest jej kontrakt. Teraz na podstawie tego interfejsu stworzyć dodatkowy pośredniczący obiekt, który będzie zawierał tą logikę która będzie służyła do logowania. Spróbujmy zacząć od wygenerowania interfejsu, używamy po raz kolejny opcji refactor -> extract interface. Nasz interfejs nazwiemy PaymentService. Oczywiście zaznaczamy metodę process i możemy przeprowadzić refaktoryzację. Czyli widać, że teraz nasza usługa FakePaymentService jest implementacją interfejsu PaymentService. Taki interfejs został faktycznie utworzony. Zawiera aktualnie jedną metodę. Gdybyśmy spojrzeli na poziom Application. To tu w zasadzie na poziomie kodu nic się nie zmieniło. Możemy teraz stworzyć klasę LoggingPaymentService, która będzie reprezentowała dokładnie ten sam interfejs, czyli utworzymy sobie nową klasę LoggingPaymentService. Ta klasa oczywiście implementuje, interfejs PaymentService. W związku z tym dodajemy również metodę process. Żebyśmy mogli zrobić delegację do naszej oryginalnej usługi, to potrzebujemy referencji do niej. W związku z tym, na podstawie wcześniejszych rozważań, dodamy konstruktor i spróbujemy podać tę zależność z zewnątrz. Mówiąc krótko mamy teraz możliwość delegowania z poziomu naszego serwisu logującego działań na poziom naszej usługi PaymentService. Jednocześnie istnieje też łatwy sposób na to, żeby wykonać logikę związana z logowaniem. Zobaczcie, że możemy też zrobić to w dowolnym momencie zarówno przed wykonaniem oryginalnej metody, jak i po jej wykonaniu. Przeniesiemy kod związany z logowaniem z oryginalnej usługi na poziom naszej usługi logującej. Pozostaje nam jeszcze zalogowanie informacji o zwracanej płatności z wykorzystaniem logera. Na koniec pozostaje nam posprzątać FakePaymentService i skonfigurować użycie naszej klasy logującej na poziomie Application. Spróbujmy uruchomić kod. I w rezultacie widzimy, że ten kod zadziałał, a na poziomie FakePaymentService nie ma ani jednej linii kodu, która byłaby z tym logowaniem powiązana. Kod jest teraz dużo bardziej czysty i jednocześnie bardzo łatwo będziemy go w stanie zmienić na taki wariant, który będzie na przykład zapisywał dane w bazie. Bardzo łatwo będzie można doprowadzić do tego, że obydwa takie zaimplementowane warianty logerów będą działały jednocześnie. Bo to jest kwestia opakowania jednego obiektu w drugi także ewidentnie widać, że wykorzystanie tego wzorca proxy, a z drugiej strony trzymanie się zasady pojedynczej odpowiedzialności pozwala nam na to, żebyśmy zrobili kolejny krok w kierunku czystego, poprawnego kodu, który będzie można dużo łatwiej testować, dużo łatwiej utrzymywać, ale też pozwoli na to, żeby być otwartym na zmiany funkcjonalności.

Zaloguj się
Rejestracja jest darmowa!

Administratorem danych jest Sages Sp. z o.o. z siedzibą w Warszawie przy ul. Nowogrodzkiej 62c. Podanie danych jest dobrowolne. Osobie, której dane dotyczą przysługuje prawo wglądu do danych osobowych, ich zmiany oraz usunięcia w sposób określony w Polityce prywatności.

Please accept the Terms and Conditions to proceed.