Czy to jest Adapter?

Julian_
  • Rejestracja:około 8 lat
  • Ostatnio:ponad 4 lata
  • Postów:1703
1

LowRider to Adaptee?
PoliceCar to AdapterImplementation?
PrivilegedCar to Adapter?

Kopiuj


package Adapter;

public interface PrivilegedCar {

	public void moveWithSiren();
	
	public void moveWithoutSiren();
}


package Adapter;

public class PoliceCar implements PrivilegedCar{
	
	private LowRider car;
	
	public PoliceCar(){
		this.car = new LowRider();
	}
	
	public void moveWithSiren(){
		System.out.println("*biu biu!* GETOUTA ROAD! *biu biu!* ");
	}
	
	public void moveWithoutSiren(){
		car.moveSlowlyInTheHood();
	}
	
	

}


package Adapter;

public class LowRider {

	public void moveSlowlyInTheHood(){
		System.out.println("havin a cool ride, dawg...");
	}
	
	public void runAwayFromPolice(){
		System.out.println("shieeeet... the cops! run!");
	}
}




package Adapter;

public class AppMain {
	public static void main(String[] args) {

		PoliceCar pc = new PoliceCar();
		pc.moveWithoutSiren();
		pc.moveWithSiren();
	
}

Jeśli tak to czy nie lepiej zrobić tak:

Kopiuj


package Adapter;

public interface CityVehicle {

	default public void moveSlowlyInTheHood(){
		System.out.println("havin a cool ride, dawg...");
	}
}


package Adapter;

public interface PrivilegedCar {

	public void moveWithSiren();
	
	public void moveWithoutSiren();
}


package Adapter;

public class PoliceCar implements PrivilegedCar, CityVehicle{
	
	
	
	public PoliceCar(){
		
	}
	
	public void moveWithSiren(){
		System.out.println("*biu biu!* GETOUTA ROAD! *biu biu!* ");
	}
	
	public void moveWithoutSiren(){
		moveSlowlyInTheHood();
	}
	
	

}


package Adapter;

public class LowRider implements CityVehicle{

	
	
	public void runAwayFromPolice(){
		System.out.println("shieeeet... the cops! run!");
	}
}


package Adapter;

public class AppMain {
	public static void main(String[] args) {

		PoliceCar pc = new PoliceCar();
		pc.moveWithoutSiren();
		pc.moveWithSiren();
		
		
	}
}
katelx
  • Rejestracja:około 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Hong Kong
2

imo to nie ma to zadnego sensu. co chcesz osiagnac?

Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
4
katelx napisał(a):

imo to nie ma to zadnego sensu. co chcesz osiagnac?

Jak to co, on chce zastosować wzorce ;)

Julian_
  • Rejestracja:około 8 lat
  • Ostatnio:ponad 4 lata
  • Postów:1703
0

chcę osiągnąć implementację adaptera. :) Nie rozumiem po co robić adapter jak można postawić interfejs z domyślnymi metodami.

Tu chodzi o to, że LowRider to auto gangu i mają metody, które nie może mieć wóz policyjny PoliceCar poza 1 metodą.
Tę 1 metodę do wożenia się po dzielnicy chce mieć też wóz policyjny.

edytowany 1x, ostatnio: Julian_
Pixello
  • Rejestracja:około 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Podkarpacie
  • Postów:448
0

Załóżmy że masz biblioteke która pozwala holować samochody.

Twoje implementacje police car i low rider nie pozwalają na bycie holowanymi

Adapterem będzie więc klasa class TowingAdapter { .ctor(Vehicle vehicle ){} void AttachToTow(Tow tow) }

Julian_
nie pozwalają na bycie holowanym to znaczy, że nie mogą być holowane czy na teraz nie ma tego w implementacji?
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:około 7 godzin
  • Postów:8423
0

Od pewnego poziomu abstrakcji tłumaczenie obiektówki na zwierzątkach, czy przedmiotach codziennego użytku czy samochodach przestaje mieć sens (no chyba, że robisz grę albo coś innego, gdzie faktycznie występują zwierzęta, lodówki czy samochody jako obiekty dziedziny).

Lepiej wziąć to na przykładzie czegoś, co naprawdę ci się przyda. Np. chcesz wyświetlać komunikaty na stronie internetowej, ale nie wiesz jeszcze jak (czy może okienko alert, czy może wyświetlić to gdzieś w środku strony za pomocą jQuery, czy może komunikaty wyświetlać tylko w konsoli debuggerskiej itp.).

Ponieważ często będziesz wyświetlał komunikaty, potencjalna zmiana decyzji może cię kosztować zamianę np. 100 wywołań funkcji alert na adekwatne 100 wywołań funkcji console.log. Jest to bez sensu, więc potrzebne ci jest coś, co pozwala bardzo łatwo się przełączać pomiędzy róznymi implementacjami i nie uzależnia cię od detali technicznych. Więc możesz zrobić sobie 3 adaptery jQueryPrinter, alertPrinter i consolePrinter i każdy będzie miał taką samą metodę print:
(kod w JavaScript)

Kopiuj

class jQueryPrinter {
   print(text) {
      $("#whatever").text(text); // wyswietla text za pomoca jQuery
   }
}

class AlertPrinter {
   print(text) {
      alert(text); // wyswietla okienko modalne z tekstem `text`
   }
}

class ConsolePrinter {
   print(text) {
      console.log(text); // wyswietla text w konsoli developerskiej
   }
}

a potem możesz operować na wyższym poziomie abstrakcji

Kopiuj
const printer = new ConsolePrinter; // albo new AlertPrinter etc.

printer.print(2 + 2);
printer.print(1000 + 200 + 30 + 4);
printer.print('Hello World');

:)


edytowany 2x, ostatnio: LukeJL
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:6 dni
  • Lokalizacja:Wrocław
2

@LukeJL: to co tu pokazałeś, to jest strategia, a nie adapter.

Adapter to taki kabelek, który z jednej strony ma HDMI, a z drugiej DVI. W programowaniu działa to dokładnie tak samo - pozwala połączyć jakiś obiekt X (stary monitor z DVI) z metodą, która przyjmuje obiekty określonego interfejsu I (czyli HDMI). Musisz w tym celu ten swój obiekt X opakować w obiekt Adapter, który będzie także implementował interfejs I (czyli kabelek konwertujący DVI na HDMI). Metody wymagane przez I w implementacji Adaptera będą w praktyce wołały metody obiektu X.

Ogólnie polecam przeczytać Head first design patterns.

edytowany 1x, ostatnio: somekind
Julian_
a to co zakodziłem to adapter?
Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:15 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
2

To co chcesz osiągnąć to jakaś forma substytucji jednego typu innym i zadziałało by to w językach z tzw. kaczym typowaniem (duck typing - jeżeli coś kwacze jak kaczka i pływa jak kaczka to jest to kaczka, choć w rzeczywistości może to być coś zupełnie innego). Wzorzec adaptera służy do tłumaczenia, adaptacji, jednego interfejsu na inny. W twoim przypadku mogło by to wyglądać tak:

Kopiuj
class LowRiderToPoliceCarAdapter implements PrivilegedCar{

	private LowRider lowRider;

	public LowRiderToPoliceCarAdapter(LowRider lowRider){
		this.lowRider = lowRider;
	}

	public void moveWithSiren(){
        	// pytanie jak lowRIder ma udawać wóz policyjny?
    	}
 
    	public void moveWithoutSiren(){
        	lowRider.moveSlowlyInTheHood();
    	}
}

I teraz masz coś co pozwala na adaptację LowRidera na samochód policyjny.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
Julian_
no wlasnie LowRider nie może udawać wozu policyjnego i jechać z syreną, a policyjny wóz nie może uciekać przed policją jak LowRider...
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:około 7 godzin
  • Postów:8423
0

Jak czytam teraz definicje adaptera i strategii z książki GoF tak na szybko to wydaje mi się, że różnica jest głównie w przeznaczeniu "do czego ta klasa może służyć" * a niekoniecznie w implementacji - w obydwu wzorcach mamy rzecz A, która chce używać jakichś niekompatybilnych interfejsów X oraz Y w ten sam sposób, więc korzysta z jakiegoś wrappera, który udostępnia jednolity interfejs B.

Ja nie widzę różnicy, chociaż możliwe, że jest.

** Z tego, co wyczytałem i jak to rozumiem, to przy adapterze zwykle mamy już gotowy jakiś interfejs, którego używamy i tylko jeden z obiektów jest “czarną owcą” i chcemy go przyrównać do pionu (czyli trochę jak UK a Europa - gniazdka inne, mile, ruch lewostronny itp.). Natomiast przy strategii startujemy od zera i żaden obiekt nie zachowuje się standardowo (czyli trochę jak XKCD 927: https://xkcd.com/927/ ).
Przynajmniej tak to rozumiem.
*


somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:6 dni
  • Lokalizacja:Wrocław
0

@LukeJL: w adapterze masz dwie rzeczy - kod operujący na obiektach implementujących dany interfejs oraz obiekt, który tego interfejsu nie implementuje. Dlatego piszesz adapter, który opakowuje ten obiekt do istniejącego kodu.
W strategii masz zestaw różnych algorytmów o wspólnym interfejsie. Ok, możesz napisać strategię, która będzie przy okazji adapterem (bo opakuje jakąś istniejącą bibliotekę, aby realizowała cele strategii), ale strategia nadal będzie jakby poziom wyżej w abstrakcji.

edytowany 1x, ostatnio: somekind
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

@somekind: jeśli mam kolejkę albo stos na przykład to implementacja z lista pod spodem będzie adapterem?


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
somekind
Masz rację, nie będzie.
katelx
  • Rejestracja:około 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Hong Kong
2
Julian_ napisał(a):

chcę osiągnąć implementację adaptera. :) Nie rozumiem po co robić adapter jak można postawić interfejs z domyślnymi metodami.

zle dobrales przyklad, wez lepiej cos gdzie adapter jest faktycznie potrzebny. np:

zalozmy ze masz nowe api do obliczania cen czegostam:

Kopiuj
interface PriceCalculator {
    Price getPrice(Instrument instr, FxConverter converter);
}

interface FxConverter {
    Price toUSD(Price price);
}

niestety nie masz za bardzo czasu zeby napisac nowy komponent do wymiany walut, za to masz dzialajace i przetestowane to:

Kopiuj
class LegacyFxConverter {
    long toUSD(String ccy, long price) {
        /* tu duzo skomplikowanej logiki etc */
    }
}

potrzebujesz wiec adaptera:

Kopiuj
class FxConverterAdapter implements FxConverter {
    LegacyFxConverter legacyConverter;

    public FxConverterAdapter(LegacyFxConverter legacyConverter) {
        this.legacyConverter = legacyConverter;
    }

    Price toUSD(Price price) {
       long usdPrice = legacyConverter.toUSD(price.getCcy(), price.getValue());
       return new Price("USD", usdPrice); 
    }
}
Julian_
  • Rejestracja:około 8 lat
  • Ostatnio:ponad 4 lata
  • Postów:1703
0

a ten interfejs PriceCalculator to po co? No, tak samo zrobiłem.

Pytanie po co tak robić skoro można przenieść implementację z LegacyFxConveter do interfejsu FxConveter jako domyślną metodę:

Kopiuj
interface FxConverter {
    default public Price toUSD(String ccy, long price){
        /* tu duzo skomplikowanej logiki etc */
    }
}


class LegacyFxConverter implements FxConveter{
    
}


class FxConverterAdapter implements FxConverter {
    
}
edytowany 3x, ostatnio: Julian_
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

@Julian_: no to teraz wyobraź sobie że to twoje "dużo skomplikowanej logiki" to jest jakiś cały moduł, cała biblioteka, moze setki klas :D I często nie da sie ot tak tej logiki przenieść kopiując jedną metodę. Zresztą duplikowanie kodu to tragiczny pomysł, bo co jak wyjdzie nowa wersja tej biblioteki? Znowu kopiujesz ten kod? No i będziesz nagle miał w projekcie ten sam kod kilka razy, co oznacza że będą błędy i niespójności.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
Julian_
nie kopiowanie tylko przeniesienie.
Shalom
Nie bo przecież ten kod wcale nie musi być "twój". To moze być kod z jakiejś biblioteki albo zupełnie innego projektu ;]
Julian_
no chyba, że tak.
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:około 7 godzin
  • Postów:8423
0

Kopiuj wklej to potężna technika XD
żeby była możliwość zrobienia sprytnego kopiuj wklej na zasadzie referencji, czyli że przeklejasz kod w 100 miejsc i w tych 100 miejscach zawsze będzie najbardziej aktualna wersja... oh, wait. Przecież do tego właśnie można wykorzystać klasy XD

nawiasem mówiąc w JS da się pracować z kodem na poziomie samych metod (bo funkcje są obiektami), więc wystarczyłoby po prostu wydzielić gdzieś jedną funkcję do osobnego modułu i ją używać, a nie bawić się w dziedziczenie.


edytowany 1x, ostatnio: LukeJL
Julian_
wytnij wklej, a nie kopij wklej !
katelx
  • Rejestracja:około 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Hong Kong
0
Julian_ napisał(a):

a ten interfejs PriceCalculator to po co?

jak to po co? przeciez napisalam ze to jest nowe api do ktorego chcesz sie dostosowac wiec potrzebujesz adapter bo masz istniejacy kod legacy ktory "nie pasuje" do nowych interfejsow.

Pytanie po co tak robić skoro można przenieść implementację z LegacyFxConveter do interfejsu FxConveter jako domyślną metodę

i trzymac caly modul do konwersji walut w interfejsie? zmieniac wszystkie dotychczasowe zaleznosci zeby uzywaly nowego sposobu? jesli twoj caly projekt to przyklad na uzycie adaptera to rzeczywiscie, nie ma to sensu. dlatego wlasnie sugeruje analizowac cos co rozwiazuje rzeczywisty problem a nie autka czy zwierzatka ktore wypisuja tekst na konsole ;)

Julian_
no ale nigdzie nie wykorzystujesz tego PriceCalculator
katelx
tzn mam wrzucic tu caly projekt w ramach przykladu? :)
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

Dobra @Julian_ w sumie znazłem w Javie dobry przykład na adaptera, tylko "lekko" schowany: private static class ArrayList<E> z Arrays.java która jest zwracana przez Arrays.asList(T... a) :)
Dzięki temu gdy masz tablicę obiektów możesz ją przekazać jako Listę, bo czasami jest tak że niektóre metody zwróca tablice np.
https://docs.oracle.com/javase/8/docs/api/java/io/File.html#listFiles--
A gdziesz będziesz chciał przekazac Liste bo jakas inna biblioteka potrzebuje jako parametru kolekcji plików a nie tablicy :)


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
somekind
No ok, to masz tablicę, potem wołasz na niej metodę asList(), dostajesz listę i przekazujesz ją do innej metody? I ArrayList<e>jest tym adapterem, a nie po prostu klasą implementującą rozszerzalną listę?
S9
ArrayList<E> w tym przypadku (bo to nie jest ArrayList z java.util.ArrayList) to widok tablicy. Wewnątrz ma stałą (final) referencję do tablicy i pozwala wykonywać operacje na niej przez API kolekcji, ale ta tablica nie może zmienić rozmiaru

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.