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:prawie 10 lat
  • Ostatnio:4 miesiące
  • Lokalizacja:Hong Kong
2

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

Pixello
  • Rejestracja:prawie 10 lat
  • Ostatnio:4 miesiące
  • 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:prawie 10 lat
  • Ostatnio:4 miesiące
  • 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:2 minuty
  • Postów:8403
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:minuta
  • 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:około miesiąc
  • 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:2 minuty
  • Postów:8403
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:minuta
  • 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:5 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:prawie 10 lat
  • Ostatnio:4 miesiące
  • 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:2 minuty
  • Postów:8403
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:prawie 10 lat
  • Ostatnio:4 miesiące
  • 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:5 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
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)