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
T-Mobile rusza z przedsprzedażą iPhone 18 Pro i Pro Max
Ta gra pokazuje wady i zalety całej branży. A to nieoczywisty przykład
Transport Fever 3 wygląda jak gra, przy której można kompletnie przepaść...
Windows 11 z gigantyczną luką po jednym dniu od rekordowej aktualizacji. Witajcie w przyszłości
Prawdziwy Tim Cook promuje nowego Samsunga. Czy to trolling roku?
Czy Apple naprawdę będzie nas podsłuchiwać? Wyjaśnijmy kontrowersyjną nowość
Domowy monitoring bez ciągnięcia kabli. Te kamery zamontujesz w 15 minut
Ta przeglądarka jest świetna, a teraz jest jeszcze lepsza. Grzech nie sprawdzić
To najdziwniejsza reklama Ikei. Mod do Skyrima z podążającą szafą Kallax
Plus wraca do gry! Rusza gigantyczna rozbudowa i modernizacja sieci
Dom 120 m2 w 48 godzin. Nowa technologia budowy bez cegły
Doładuj T-Mobile i zgarnij hot-doga za darmo
Dodali jeden składnik do baterii. Efekt przerósł wszelkie oczekiwania
HUAWEI FreeBuds Neo – recenzja. Za 449 zł oferują zaskakująco dużo
ChatGPT idzie po finanse. Czy jest branża, której nie opanuje?
Nowa Tesla stanowi zagrożenie? Strażacy mają sporo obaw
Leapmotor B03X. Jeździłem elektrykiem "dla każdego"
Lidl sprzedaje tani lokalizator za grosze — alternatywa dla AirTaga
Powraca kultowy serial. Nowa wersja może niektórych zszokować
Microsoft szykuje rewolucję. Aż 9 poprawek jednej funkcji
Świat upomina się o „właściwe” proporcje
Kosmiczna panorama i superkoronograf – co przyniesie nam Teleskop Nancy Roman?
O czym szepczą między sobą bozony Higgsa?
Wszechświat w trzech aktach – recenzja książki “Astronomia, kosmologia i astronautyka”
Wielka przerwa Wielkiego Zderzacza
A gdyby tak przeciąć foton na pół?
SpudCell – syntetyczna komórka, która udaje życie
Mega upał, omega manipulacja
Coraz więcej dowodów, coraz mniej pewności
Matematyczno-restauracyjny dylemat Ryszarda
Tańszy Game Pass, droższy Steam Deck i Internet 0202122 – Odcinek #135
Elite Dangerous. Gra, z której odchodzi się po cichu
Gry zasługujące na adaptację filmową – Odcinek #134
Relacja z RePlay Fest 2026
Najlepsze intra i openingi w grach – Odcinek #133
AI, Star Trek, Rycerz Siedmiu Królestw, Festiwal dem na Steam Next Fest – Odcinek #132
Gry, filmy i seriale w 2025 i 2026 roku – Odcinek #131
30 lat konsoli PlayStation – Odcinek #130
Omawiamy serię The Walking Dead (gość: Stary Gracz)
Nikt nie potrzebuje cienkich smartfonów – Odcinek #129

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.