Adapter

Do czego służy wzorzec Adapter?
Zaliczamy do wzorców strukturalnych. Dzięki niemu, możemy zmusić do pracy dwa obiekty o niekompatybilnych interfejsach. Postaram się wytłumaczyć ten wzorzec na przykładzie płyty indukcyjnej i garnków, które nie działają na płycie indukcyjnej, czyli takich bez dna ferromagnetycznego. Jak widać na pierwszy rzut oka, coś jest nie tak. Garnki nie pasują do płyty, czy to znaczy że nic się już nie da zrobić i trzeba kupić nowe garnki? Otóż stosując adapter na płytę indukcyjną, jesteśmy w stanie używać wszystkich garnków, które nie zostały przystosowane na kuchenkach indukcyjnych. Tak samo działa wzorzec projektowy adapter.
inductionHob (PotWithoutFerromagnetic) ?
Zacznijmy od uchwycenia problemu w kodzie. Poniżej zamieściłem klasy: InductionHob, GasStove, PotWithFerromagnetic, PotWithoutFerromagnatic.
Jak widać w poniższych klasach, garnki z ferromagnetykiem oraz garnki bez ferromagnetyka nagrzewają się poprzez różne systemy: inductionOn() lub burnerOn(). Stwórzmy zatem demo do tego programu i zobaczmy czy garnek PotWithoutFerromagnetic zadziała na płycie indukcyjnej.
public class Main {
public static void main(String[] args) {
PotWithoutFerromagnetic garnek = new PotWithoutFerromagnetic() {
@Override
public void burnerOn() {
System.out.println(„Gotuję się!”);
}
};
GasStove kuchenkaGazowa = new GasStove();
kuchenkaGazowa.startCooking(garnek); //działa: „Gotuję się!”
InductionHob plytaIndukcyjna = new InductionHob();
plytaIndukcyjna.startCooking(garnek); // nie działa
}
}
public class InductionHob {
public void startCooking(PotWithFerromagnetic pot) {
pot.inductionOn();
}
}
public class GasStove {
public void startCooking(PotWithoutFerromagnetic pot) {
pot.burnerOn();
}
}
public interface PotWithFerromagnetic {
void inductionOn();
}
public interface PotWithoutFerromagnetic {
void burnerOn();
}
Mission failed
"java: incompatible types: patterns.adapter.PotWithoutFerromagnetic cannot be converted to patterns.adapter.PotWithFerromagnetic", czyli przekładając na język ludzki po prostu to nie zadziała.
Jeżeli staramy się garnek bez ferromagnetyka zagotować na płycie indukcyjnej to wyskakuje błąd, program się działa. Bez specjalnego adaptera nic nie zrobimy. Pokażę teraz jak działa adapter.
Adapter - schemat działania

Aby podgrzewać garnek bez ferromagnetyka na płycie indukcyjnej zastosujemy adapter ForInductionAdapter.
Teraz wystarczy tylko stworzyć w demo adapter i użyć go do nie pasującego garnka:
public class Main {
public static void main(String[] args) {
PotWithoutFerromagnetic garnek = new PotWithoutFerromagnetic() {
@Override
public void burnerOn() {
System.out.println(„Gotuję się!”);
}
};
GasStove kuchenkaGazowa = new GasStove();
kuchenkaGazowa.startCooking(garnek); //działa: „Gotuję się!”
InductionHob plytaIndukcyjna = new InductionHob();
ForInductionAdapter adapter = new ForInductionAdapter(garnek);
plytaIndukcyjna.startCooking(adapter); //działa: „Gotuję się!”
}
}
public class InductionHob {
public void startCooking(PotWithFerromagnetic pot) {
pot.inductionOn();
}
}
public class GasStove {
public void startCooking(PotWithoutFerromagnetic pot) {
pot.burnerOn();
}
}
public interface PotWithFerromagnetic {
void inductionOn();
}
public interface PotWithoutFerromagnetic {
void burnerOn();
}
public class ForInductionAdapter implements PotWithFerromagnetic{
PotWithoutFerromagnetic pot;
public ForInductionAdapter(PotWithoutFerromagnetic pot) {
this.pot = pot;
}
@Override
public void inductionOn() {
pot.burnerOn();
}
}
Podsumowanie
To wszystko powyżej to podstawowa implementacja wzorca adapter. Można spotkać się jeszcze z adapterem dwukierunkowym, który za pośrednictwem jednej klasy adaptera, mógłby działać dwukierunkowo, tzn. łączyć garnek bez ferromagnetyka z płytą indukcyjną oraz łączyć garnek z ferromagnetykiem z kuchenką gazową.
Największą wadą adaptera jest to, że dodaje dodatkowy poziom abstrakcji między naszymi komponentami. Pomimo swoich wad wzorzec adapter jest często używanym wzorcem.
