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 – Adapter
  • Programowanie
  • Wszystko

Wzorce projektowe – Adapter

Jakub Raczkowski 24 stycznia 2024

Świat nie jest idealny. Wielokrotnie przyjdzie nam stawiać czoła problemom wynikającym z różnych niedoskonałości, czy to zeszłych czy też tych dopiero wprowadzonych. Aby im sprostać musimy nauczyć się improwizować i adaptować. Panie i panowie – oto Adapter.

Dzisiejszy wpis miał być poświęcony dwóm wzorcom: Adapterowi oraz Fasadzie, które faktycznie są do siebie trochę podobne, ale też na tyle różne, że chcąc je zmieścić w jednym artykule musiałbym albo go niemiłosiernie rozwlec, albo pozbawić wartościowych informacji. Lepiej zatem będzie jeśli rozłożymy to na dwie części.

Zacznijmy zatem od nakreślenia problemu, który rozwiąże nasz Adapter:

Macie własną appkę – pogodynkę. Dane meteorologiczne pobierane są ze stacji pogodowej zamontowanej na balkonie. Póki co wszystko działa elegancko, ale kupujecie nową stację z jeszcze lepszymi możliwościami… która temperaturę zwraca w stopniach Kelvina. Wszystko macie ustawione pod Celsjusza, więc nowe wyniki wyświetlane są kuriozalnie – co robicie?

public class Temperature{

void showTemperatureCelcius(Meteo meteo){
//obiekt 'meteo' zawiera wszystkie dane ze stacji
	show(meteo.getTemperature)
	}
}

Odpowiedź nasuwa się sama – zmieniacie klasę odpowiedzialną za wyświetlanie temperatury. Owszem, można, ale zgodnie z zasadą Otwarty/Zamknięty nazwijmy to planem B. Czy da radę coś z tym zrobić bez modyfikacji klasy klienta?

A jakże. Możemy skorzystać z wzorca Dekorator o którym już mówiliśmy. Stworzymy nową klasę, która opakuje klasę odpowiedzialną za wyświetlanie temperatury i podmieni wyniki:

Decorator decorator = Decorator(new Temperature);
decorator.showTemperatureCelcius(meteo);

Rozwiązanie proste i szybkie. Czego chcieć więcej?

Stacja pogodowa. Źródło: Allegro.

W zasadzie wszystko jest już na swoim miejscu, problem może pojawić się jedynie kiedy takich dekoracji trzeba będzie zrobić więcej. Wtedy zauważymy, że liczba dodatkowych linijek rośnie i zaczyna zaciemniać kod. Przydałaby się bardziej elegancka solucja. I tu właśnie do gry wchodzi adapter.

O ile Dekorator „przypudrowuje” stary obiekt, tak aby spełniał nasze oczekiwania, o tyle Adapter podmienia go na nowy, na dokładnie taki jakiego potrzebujemy. Aby sobie to lepiej zobrazować weźmy za przykład auto. Stary gruz, który jakimś cudem wciąż jeździ i dowozi nas do pracy.

Klasyka się nie starzeje.

Ale my chcemy czegoś nowszego. Wydajemy więc kupę kasy na mechanika, lakiernika, blacharza i wulkanizatora, a na koniec kupujemy jeszcze Wunderbauma… gotowe! Autko wygląda jak nowe, a do tego pachnie sosenką!

Albo możemy inaczej – odstawiamy gruchota, a na jego miejsce kupujemy świeższy egzemplarz. Wszystko rozbija się o kwestię ceny – czasami w starszym modelu wystarczy wymienić opony, klocki i olej, wtedy nie ma co jeszcze myśleć o kupnie nowego samochodu. Ale czasami pracy jest tyle, że taniej nam wyjdzie zainwestować w coś prosto z salonu.

Przed podobnym dylematem możecie stanąć kiedy przyjdzie wam wybierać pomiędzy zastosowaniem Dekoratora i Adaptera próbując dostosować tzw. legacy code do swoich wymogów. Przypomnijmy definicję tego pierwszego i porównajmy z Adapterem:

Dekorator – pozwala na dynamiczne przydzielanie danemu obiektowi nowych zachowań. Dekoratory dają elastyczność podobną do tej, jaką daje dziedziczenie, oferując jednak w zamian znacznie rozszerzoną funkcjonalność.

Wzorzec Adapter dokonuje konwersji intrfejsu danej klasy do postaci innego interfejsu, zgodnego z oczekiwaniami klienta. Adapter pozwala na wzajemną współpracę klas, które ze względu na niekompatybilne interfejsy wcześniej nie mogły ze sobą współpracować.

Rusz głową! Wzorce projektowe

Dynamiczne przydzielanie vs. konwersja. Decyzja należy do nas.

Obrazek wygenerowany, Bing AI.

Ale po kolei…

Jak zbudować dobrą drużynę?

A co znaczy „dobrą„? Chodzi o skuteczność? Czy o ciekawe prowadzenie? A może zależy nam na interakcjach pomiędzy członkami zespołu? Tu za przykład weźmy grę Icewind Dale, gdzie od samego początku tworzymy własny zespół wybierając klasy i losując statystyki. Od zera do bohatera.

Można naturalnie stworzyć sześciu siepaczy, i przejść w ten sposób całą grę. Już pomijając monotonię takiego podejścia, trzeba brać pod uwagę ograniczoną ilość ciekawych artefaktów – jednego albo dwóch wojowników jako tako ubierzemy, a reszta będzie musiała ganiać w skórzanych zbrojach. Zróżnicowany zespół to interesująca rozgrywka, równomierny podział lootu oraz masa taktyk z których znajdziemy coś na każdą okazję. Łotrzyk skrytobójca, łowca szyjący z dystansu, tarczownik biorący na siebie impet wroga, czarodziej kontrujący wrogich magów, no i rzecz jasna jakiś healer.

Kapłan czy druid?

Sernik z rodzynkami czy bez? Można wziąć to i to, ale większość zaklęć będzie się pokrywać. To też przydatne, bo im więcej czarów leczenia tym drużyna dłużej pociągnie. Ja jednak bardziej skłaniam się ku druidowi – co prawda nie wzmocni zespołu buffami tak dobrze jak rasowy kleryk, ale za to przywoła, albo oczaruje jakieś zwierzaki aby walczyły po naszej stronie. Szczególnie na początku rozgrywki to nieoceniona pomoc.

Druidka. Źródło.

Przejdźmy do sedna – jak w kodzie sprawić aby przeciwnik stał się sprzymierzeńcem? W końcu oba korzystają z różnych interfejsów.

Spójrzcie poniżej. Pełny kod jak zwykle na GitHubie.

Nie można leczyć wrogów.

Adaptera używa się aby zniwelować różnicę w interfejsach. Mamy więc brunatnego miśka, który jest naszym wrogiem (interfejs Enemy) i jako takiego nie możemy go leczyć – leczenie działa tylko na sprzymierzeńców (interfejs Ally).

Na szczęście nasz druid ma metodę speakWithAnimals(Enemy enemy) która bierze tego złego niedźwiadka i adaptuje go na przyjaciela:

CODE
Ally speakWithAnimals(Enemy enemy){
            System.out.println("Druid rzuca czar 'Rozmowa ze zwierzętami': " + enemy);
            if (enemy instanceof BrownBear) {
                System.out.println("[Sukces. Otrzymano nowego sojusznika.]");
                return new EnemyToAllyAdapter(enemy);
            }
            return null;
        }
Adapter implementuje docelowy interfejs Ally, ale do konstruktora bierze ten bazowy: Enemy.

I już wszystko działa jak trzeba – uszatek co prawda teraz strzela do własnej bramki, ale za to możemy go leczyć i miziać po brzuszku (funkcja do zaimplementowania w przyszłości).

Teraz już wszystko bangla elegancko.

ITCandidateEvaluator

Sytuacja wygląda dokładnie tak samo jak przy Dekoratorze. Biorąc pod uwagę, że projekt zaczynam od zera i robię go w pełni samodzielnie – wysoce wątpliwe jest abym musiał tworzyć jakiekolwiek adaptery. Jeśli jakiś interfejs będzie mi potrzebny to go po prostu zaimplementuję do danej klasy jeszcze w czasie jej tworzenia. I po kłopocie.

Wzorce dekorator i adapter mają najwięcej racji bytu przy operowaniu na starszym kodzie, a w dodatku nie naszym i pozbawionym testów. Wtedy jakakolwiek modyfikacja nawet najmniejszej metody to stąpanie po kruchym lodzie – nigdy nie wiemy co spieprzymy podmieniając choćby i jedną, z pozoru nic nie znaczącą zmienną.

Ja takiego problemu (na razie) nie mam dlatego zapraszam do kolejnego odcinka gdzie zajmiemy się wzorcem Fasada.

Tags: design patterns programming

Continue Reading

Previous: Wzorce projektowe – Command
Next: Wzorce projektowe – Facade

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
AirPodsy 5 nieźle namieszały. Które słuchawki Apple warto teraz wybrać?
Apple Watch Ultra 4 bez fajerwerków. Czy mimo to warto go kupić?
Elon Musk zamówił LEGO i uruchomił lawinę złośliwości. Nie wierzcie mu na słowo
Oto tatuaż, który można włączyć i wyłączyć. Badacze stworzyli niemożliwe?
iPhone 18 Pro ma coś, czego wcześniej nie miał żaden iPhone
Używasz starej karty SD? To duży błąd
To jeden z największych problemów komputerów kwantowych. Jesteśmy krok bliżej przełomu
Pierwszy, poważny dowód na nieznaną planetę Układu Słonecznego? Oto on
Wegetarianie kontra mięsożercy. Badanie rozstrzyga kto łatwiej zbuduje mięśnie
Garmin Fenix 9 Pro na cenzurowanym. Deweloperzy narzekają na błędy
Darmowy upgrade telewizora. Włącz te 3 ustawienia
To może być największy serial sci-fi tego roku. Blade Runner 2099 coraz bliżej
LEGO szykuje prawdziwe perełki na 2027 rok. Niektóre mogą kosztować fortunę
Microsoft ubija kolejną funkcję znanej aplikacji
Parkside pomoże ogarnąć ogród i taras. Ceny zaczynają się od 24,99 zł
GTA VI to wisienka na torcie. Jesień na Xbox to wysyp innych hitów
Głośnik jak karton mleka. Takiej nietuzinkowej technologii nam trzeba
Prawdziwy wysyp hitów na PS5. Ta jesień przejdzie do historii
Przyspiesz Windows 11 bez pobierania żadnych apek
Użytkownicy Windowsa popełniają duży błąd. Ekspert tłumaczy zły nawyk
IceCube – miliard ton lodu, żeby dorwać neutrino
O powstawaniu kamieni drogą doboru naturalnego
Ś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
Wyglądają i grają jak premium, a kosztują ułamek tej ceny. Recenzja Baseus Inspire XH1
W co grać W PAŹDZIERNIKU? Nowe Star Wars Racer, powrót Gears of War
Team Xbox, team OLED i nowe Avengersy – Odcinek #138
WRZESIEŃ BĘDZIE MOCNY… Premiery gier, na które czekamy – Mamy do pogrania
Całkiem dobry film ten nowy Spider-Man: Brand New Day 🕷️ – No Movie Ci #18
Scyzorykon 2026, Galaxy Fold8 i całkiem nowy Spider-Man – Odcinek #137
Sprawdziliśmy Scyzorykon 2026 od środka!
Co się działo na Fantasy & Magic Con w Warszawie?
Porozmawiajmy o Steam Machine 🎮👀
Przedsprzedaż GTA VI, Stargate i gry, które paliły sprzęty – Odcinek #136

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.