Skip to content

Witaj w Świecie Jutra!

  • Technologie jutra
  • Sprzęt jutra
  • Aplikacje jutra
  • Programowanie
  • Księga Drogi
  • Renowacja
  • Różności
  • Archiwum
  • Autor
  • Home
  • Wszystko
  • Wzorce projektowe – Proxy
  • Programowanie
  • Wszystko

Wzorce projektowe – Proxy

Jakub Raczkowski 30 stycznia 2024

Kadr z filmu "Zabójcza broń"

Jeśli spojrzymy na definicje wzorców które dotychczas udało nam się poznać, to formułka opisująca Proxy jest z nich wszystkich najkrótsza. Dość ironicznie, bo „Pośrednik” jest również najtrudniejszy.

Zacznijmy zatem od teorii:

Proxy – zastępuje inny obiekt i kontroluje dostęp do niego.

Rusz głową! Wzorce projektowe

Tyle. Osiem słów. A jak przyjdzie co do czego to w grę wchodzą rejestry sieciowe, buforowanie, firewall, Reflection API i sporo innych trudnych słówek.

Definicja wzorca trochę mylnie sugeruje podobieństwo do Adaptera, który też przecież zastępuje inny obiekt. Różnica tkwi w tym, że Adapter robi to TYLKO po to aby zniwelować różnicę w interfejsach, natomiast Proxy ma inne, znacznie bardziej zróżnicowane zastosowania. Dla przykładu:

  • RemoteProxy pośredniczy w wymianie informacji pomiędzy klientem i serwerem
  • VirtualProxy pośredniczy w dostępie do obiektów, których utworzenie wymaga sporo czasu/mocy obliczeniowej
  • ProtectionProxy chroni obiekt przed nieupoważnionym dostępem
  • CachingProxy buforuje obiekty z których często korzystamy
  • SynchronizationProxy zapewnia bezpieczny dostęp do obiektu w środowisku wielowątkowym

A to dopiero początek listy. Jeśli chciałbym opisać każdy rodzaj pośrednika musiałbym poświęcić na to tyle samo artykułów ile dotąd stworzyłem z tej serii. I kto wie, może to kiedyś nastąpi, ale dzisiaj zajmiemy się chyba najprostszym z nich – ProtectionProxy, który w swojej podstawowej implementacji do złudzenia przypomina coś co już przerabialiśmy: wzorzec Dekorator.

Ale po kolei…

W latach 80-tych i 90-tych swoje triumfy święciły filmy akcji o parach „gliniarzy” (tzw. Buddy Cop, choć nie zawsze byli stricte policjantami) na tropie wielkich afer. „Zabójcza Broń” z obrazka tytułowego to chyba najbardziej rozpoznawalny przykład, ale były też takie perełki jak „Tango i Cash”, „Bad Boys”, „Faceci w czerni”, „Starsky & Hutch” czy moje ulubione „Godziny szczytu”.

„Godziny szczytu” – świetny duet!

Kumple zawsze byli łączeni ze sobą na zasadzie przeciwieństw. Flirciarz i przykładny małżonek, poważny i wyluzowany, zorganizowany i spontaniczny. Prowadziło to do wielu zabawnych sytuacji, na początku współpraca przebiegała opornie, a w końcówce obaj bohaterowie ratowali sobie na zmianę tyłki.

Podobnie jest z ProtectionProxy i obiektem któremu pośredniczy.

W wielu z wymienionych powyżej produkcji (o ile nie we wszystkich) znajduje się scena przesłuchania podejrzanego. Pojawia się motyw:

Dobry i zły glina (Starsky i Hutch)

Ten zły krzyczy, grozi, szarpie i dusi bandytę, próbując wydobyć z niego informacje. Jeśli to nic nie daje, wtedy pojawia się ten dobry, przynosi jedzenie, poprawia zatrzymanemu marynarkę i zatroskanym tonem prosi o współpracę obiecując ulgowe traktowanie. Nawiązuje się nić porozumienia, bandzior daje za wygraną i opisuje dokładnie gdzie tego wieczoru nastąpi transakcja.

Ale żeby dojść do tego momentu, gangster wpierw musi zostać „zmiękczony” przez złego glinę. Naszego pośrednika ProtectionProxy (PP).

Zwykły obiekt ma swoje metody i zrobi dla nas co tylko chcemy – to ten dobry glina. Zadaniem PP (złego gliny) jest dopuszczenie do niego tylko konkretnego klienta (bandziora z ważnymi informacjami).

Na dzisiaj przygotowałem dwa przykłady jak działanie PP mogłoby wyglądać w kodzie. Wersja pierwsza (kod tutaj) jest łatwiejsza do ogarnięcia – to nic więcej aniżeli dostosowany Dekorator, który zamiast dodawać nowe metody blokuje dostęp do tych, które obiekt dekorowany posiada.

Druga wersja (kod) w działaniu nie różni się od poprzedniczki, ale oparta została na tzw. DynamicProxy czyli Proxy tworzonym już w czasie działania programu za pomocą instrukcji w klasie implementującej interfejs InvocationHandler.

Ale zacznijmy od tej prostszej:

ProtectionProxy na bazie Dekoratora

Sprawa jest jasna – jeśli skrzynia jest „niechroniona” zarówno czarodziej jak i łotrzyk mają do niej swobodny dostęp. Ale gdy opakujemy skrzynię w PP, już tylko łotrzyk – jako postać umiejąca otwierać zamki – jest uprawniony do jej otwarcia:

public void open(Character character) {
            if (character instanceof Rogue){
                System.out.println(character + " Udało się otworzyć zamek!");
                treasure.open(character);
            }
            else System.out.println(character + " Skrzynia zamknięta. Potrzebujesz klucza albo wytrychów.");
        }

Przykład jest banalny i możecie się zastanawiać, dlaczego tego if-a od razu nie dałem w klasie Chest. Cóż, w ten sposób hermetyzujemy warunek i nie musimy modyfikować klasy Skrzynia w przyszłości jeśli np. chcielibyśmy dodać czarodziejowi zaklęcie otwierania zamków. Czasami też jeden PP chroni dostęp do różnych obiektów, którym wystarczy wtedy dodać interfejs znacznikowy (bez metod).

Drugi kod robi to samo za pomocą klasy LockedChestHandler implementującej interfejs InvocationHandler z jedną metodą: invoke().

ProtectionProxy w wersji Dynamic Proxy

Nie powiedziałbym, że metoda jest zrozumiała już na pierwszy rzut oka, dlatego spróbujmy ją trochę rozjaśnić. Zapodajmy jednak wcześniej kod tworzący owe proxy z metody main():

Treasure lockedTreasure = (Treasure) Proxy.newProxyInstance(
                treasure.getClass().getClassLoader(),
                treasure.getClass().getInterfaces(),
                new LockedChestHandler(treasure)
        );

Zaczynamy od stworzenia instancji Proxy – nie za pomocą tradycyjnego konstruktora z „new„, ale osobną metodą przyjmującą trzy parametry:

  • ClassLoader klasy/abstrakcji z jakiej pochodzi nasz obiekt
  • listy interfejsów z jakich korzysta
  • oraz odwołania do klasy „Handlera” którą stworzyliśmy wcześniej

ClassLoader to komponent JVM służący do „ładowania” klasy, uzyskujemy go poprzez Odbicie (Reflection API) podobnie jak listę interfejsów. Ważne jest również aby powstały w ten sposób PP przerzutować na docelowy typ (Treasure w naszym wypadku) bo metoda newProxyInstance() zwraca tylko i wyłącznie instancje klasy Obiekt.

if (method.getName().equals("open")) {
                Character character = (Character) args[0];
                if (character instanceof Rogue) {
                    System.out.println(character + " Udało się otworzyć zamek!");
                    return method.invoke(treasure, args);
                } else {
                    System.out.println(character + " Skrzynia zamknięta. Potrzebujesz klucza albo wytrychów.");
                    return null;
                }
            }
            return null;

Kiedy już wrzucimy do metody potrzebne parametry, dynamiczne proxy jest budowane wedle wzoru z metody invoke() – nie wywołujemy jej samodzielnie. Jej parametry: (Object proxy, Method method, Object[] args) są uzyskiwane z załączonego wcześniej ClassLoadera oraz interfejsów.

Object proxy to obiekt dla którego tworzymy pośrednika. U nas jest to klasa z metodą invoke() czyli LockedChestHandler. Ten parametr jest tam na wypadek gdyby owa klasa miała jeszcze jakieś własne metody do wywołania. Ale u nas nie ma więc tego obiektu w kodzie nie używamy.

Method method to metoda w klasie Chest z której chcemy skorzystać. Zauważmy warunek:

if (method.getName().equals("open"))

To oznacza, że tylko wywołanie metody open() będzie szło przez pośrednika! Wywołanie jakichkolwiek innych metod zwróci wartość null.

Object[] args to z kolei parametry jakie przyjmuje nasza metoda open(). W przypadku skrzyni to tylko obiekt typu Character i to właśnie nań musimy rzutować aby stworzyć niezbędny warunek:

Character character = (Character) args[0];
if (character instanceof Rogue) ...

Pamiętajmy też, że metoda invoke() zwraca typ Object, dlatego musimy albo zwrócić null jeśli warunek nie przejdzie, albo:

return method.invoke(treasure, args);

Uff. Koniec.

ITCandidateEvaluator

W założeniu mój drugi samodzielny projekt ma powstać w dwóch wersjach. Ta, za którą wezmę się już niebawem ma działać lokalnie i w wersji okienkowej. Tutaj nie będą potrzebni mi żadni pośrednicy.

Wersja 2.0 którą mam nadzieję stworzę w nieokreślonej przyszłości ma być aplikacją webową. W tym wypadku jest spora szansa, że jakieś Proxy może się pojawić. Nie wiem tylko czy Spring, którego jeszcze nie tknąłem, nie załatwi pośredników za mnie. Przy okazji – o rzeczonym frameworku też chcę wyskrobać parę artykułów, jak tylko będę na to gotowy.

Proxy był ostatnim ze standardowych wzorców opisanych w książce Rusz głową! Co wcale nie oznacza, że dziś kończymy przygodę – zostały jeszcze wzorce dodatkowe, omówione pobieżnie, z których już wybrałem Buildera na temat kolejnego odcinka. Jest zwyczajnie zbyt ważny aby go pominąć.

Do następnego!

Tags: design patterns programming

Continue Reading

Previous: Wzorce projektowe – State
Next: Wzorce projektowe – Builder

Related Stories

Mageege Moon104 – test niskoprofilowego mechanika
  • Sprzęt

Mageege Moon104 – test niskoprofilowego mechanika

11 marca 2025
Przebranżowienie cz.4
  • Programowanie

Przebranżowienie cz.4

27 lutego 2025
Smartfon Jutra
  • Sprzęt

Smartfon Jutra

15 lutego 2025

Ze świata

  • Antyweb
  • Kwantowo
  • Dwóch po dwóch
Coś jest w centrum Drogi Mlecznej. Czy to właśnie tego szukamy?
Radio nie do zdarcia: ponad 18,5 mln Polaków nie pozostawia złudzeń
AI upodobni się do... iOS lub Androida. Niewiarygodne, ale jednak
Pixel 10a zadebiutuje już za 2 tygodnie. Tak będzie wyglądał
Falcon 9 uziemiony. Mogło się skończyć tragedią
Lisa Su zapowiada nowego Xboxa. Znamy potencjalną datę premiery
Płacą w telefonach i telewizorach za korzystanie z AI. Całkiem odlecieli
Za ten owoc można dostać kilkadziesiąt tysięcy złotych. Dlaczego jest taki drogi? 
Keanu Reeves wraca na ekrany! Czy Apple powtórzy sukces Formuły 1?
Szybko poszło! "Reddit dla AI" już zaliczył koszmarny wyciek danych
Rewolucja na Marsie. Nie potrzebna już kontrola człowieka
Polowanie na użytkowników OtoMoto. Można stracić pieniądze
Najnowszy model Garmina w rekordowo niskiej cenie. Do tego Spotify za darmo
Nieoczywista złota kura Apple. Niedługo zarobią jeszcze więcej
T-Mobile odpala petardę - prawie tak tanio jak w Nju Mobile
Apple chce w tym roku zaszaleć. Szykujcie się na niespodzianki co tydzień
e-PIT odcina użytkowników. Dostęp do usługi zostanie wyłączony
Nowy Samsung Galaxy już niedługo. Czego możemy się spodziewać po nowym flagowcu Samsunga?
Początek kłopotów Muska. Policja wdarła się do biur
Samsung odcina flagowca. Ten smartfon już nie otrzyma aktualizacji
To by było na tyle, jeśli chodzi o możliwość ugody
Ocalić od zapomnienia
Ostatni kwant
ALH 84001 – meteoryt, o którym mówiono nawet w Białym Domu
HESS zarejestrował kosmiczny elektron o niespotykanej energii [Phys. Rev. Lett.]
Matka ciemnej materii – recenzja biografii “Vera Rubin. Życie”
Satelita, który zerwał się ze smyczy
Wiadomość od Carla Sagana do przyszłych eksploratorów Marsa
Ile najdłużej może trwać zaćmienie Słońca?
Nowa największa liczba pierwsza ma ponad 41 milionów cyfr [GIMPS]
30 lat konsoli PlayStation – Odcinek #130
Omawiamy serię The Walking Dead (gość: Stary Gracz)
Nikt nie potrzebuje cienkich smartfonów – Odcinek #129
To ostatni dzwonek na kolekcjonowanie gier i filmów
Najlepsza relacja z PGA 2025 (Poznań Game Arena)
Bumblebee wśród klawiatur. Marvo Meqa 80W – recenzja
Pierwsze spotkanie z Omoda 7 Super Hybrid
Logitech MX Master 4, Wednesday, 1670 sezon 2 – Odcinek #128
Tani pad, który chciał być jak DualSense. Test Monka Contra GT-96
Secret Service i prasa komputerowa w Polsce – Odcinek #127

To może cię zainteresować:

Mageege Moon104 – test niskoprofilowego mechanika
  • Sprzęt

Mageege Moon104 – test niskoprofilowego mechanika

11 marca 2025
Przebranżowienie cz.4
  • Programowanie

Przebranżowienie cz.4

27 lutego 2025
Smartfon Jutra
  • Sprzęt

Smartfon Jutra

15 lutego 2025
Czym jest Swagger?
  • Programowanie

Czym jest Swagger?

22 lipca 2024
  • Technologie jutra
  • Sprzęt jutra
  • Aplikacje jutra
  • Programowanie
  • Księga Drogi
  • Renowacja
  • Różności
  • Archiwum
  • Autor
Copyright © All rights reserved. | DarkNews by AF themes.