Wzorzec Adapter
tworzy interfejs dla istniejącej klasy, tak aby wyglądał on jak interfejs innej klasy.
Zadanie programistyczne
Smoki prowadzą książkę adresową. Do tej pory ewidencjonowano smoki mieszkające
na nizinach czyli w sposób opisany w klasie AdresNizinny
. Teraz niestety doszło
ewidencjonowanie adresów smoków mieszkających w górach, których adresy zapisuje
zupełnie inaczej. Smoczyca Programistka otrzymała zadanie napisania
klasy adapterowej umożliwiającej łatwe zapisywanie obu typów adresów.
Rozwiązanie 1 (przez dziedziczenie)
- Stworzyć interface
AddresValidator
dopasowany do klasyAdresNizinny
- Zaimplementować ten interfejs w klasie
AdresNizinny
- Stworzyć klasę
AdresGorski
- Stworzyć klasę
AdresGorskiAdapter
pozwalającą na walidację adresu AdresGorski tak jakby on był
typuAdresNizinny
. KlasaAdresGorskiAdapter
rozszerza klasę
AdresGorski
i implementuje interfaceAdresValidator
- Napisać klasę
Smok
pozwalającą wpisywać i walidować adresy niezależnie
od ich typu zapisania. W metodagetValidator
w przypadku klasyAdresGorski
zwracaAdapter
! Gdyby w klasachAdresGorski
iAdresNizinny
wszystkie
pola były typuString
to klasaSmok
miałaby jeden konstruktor. - Napisać klasę
Main
i sprawdzić czy to działa.
Klasy
Klasa Smok
package adapter.inheritance; class Smok { private static final String ADRES_GORSKI = "AG"; private static final String ADRES_NIZINNY = "AN"; private String name; private final String prowincja; private final String miejscowosc; private String gora; private final String typ; private int nrJaskini; public Smok(String name, String prowincja, String systemGorski, String gora, String typ) { this.name = name; this.prowincja = prowincja; this.miejscowosc = systemGorski; this.gora = gora; this.typ = "AG"; } public Smok(String name, String prowincja, String miejscowosc, int nrJaskini, String typ) { this.name = name; this.prowincja = prowincja; this.miejscowosc = miejscowosc; this.nrJaskini = nrJaskini; this.gora = String.valueOf(nrJaskini); this.typ = "AN"; } public boolean isValidAddress() { // get an appropriate address validator AddressValidator validator = getValidator(typ); // Polymorphic call to validate the address return validator.isValidAddress(prowincja, miejscowosc, nrJaskini); } private AddressValidator getValidator(String typ) { AddressValidator validator = null; if (typ.equals(Smok.ADRES_GORSKI)) { validator = new AdresGorskiAdapter(); } if (typ.equals(Smok.ADRES_NIZINNY)) { validator = new AdresNizinny(); } return validator; } public String getGora() { return gora; } public void setGora(String gora) { this.gora = gora; } public String getName() { return name; } public void setName(String name) { this.name = name; } }// end of class
Klasa AdresNizinny
package adapter.inheritance; class AdresNizinny implements AddressValidator { @Override public boolean isValidAddress(String prowincja, String miejscowosc, int nrJaskini) { if (prowincja.trim().length() != 2) { return false; } if (miejscowosc.trim().length() < 1) { return false; } return nrJaskini >= 1; } }
Klasa AdresGorski
package adapter.inheritance; class AdresGorski { boolean isValidAddressGorski(String prowincja, String systemGorski, String gora) { if (prowincja.trim().length() != 2) { return false; } if (systemGorski.trim().length() < 1) { return false; } return !gora.trim().equals(""); } }
Klasa AdresValidator
package adapter.inheritance; interface AddressValidator { boolean isValidAddress(String prowincja, String miejscowosc, int nrJaskini); }
Klasa AdresGorskiAdapter
package adapter.inheritance; public class AdresGorskiAdapter extends AdresGorski implements AddressValidator { @Override public boolean isValidAddress(String prowincja, String miejscowosc, int nrJaskini) { return isValidAddressGorski(prowincja, miejscowosc, String.valueOf(nrJaskini)); } }
Klasa Main
package adapter.inheritance; class Main { public static void main(String[] args) { Smok smok = new Smok("Vellys", "AG", "Pomiechówek", 7, "AN"); System.out.println(smok.isValidAddress()); Smok smok1 = new Smok("Vollys", "AS", "Zakopane", "Jaskinia", "AG"); System.out.println(smok1.isValidAddress()); } }
Wynik
true true
Rozwiązanie 2 (z użyciem kompozycji)
- Tworzymy klasę abstrakcyjną
AdresWalidator
- Klasa
AdresNizinny
jest implementacją tej klasy - Tworzymy klasę
AdresGorski
- Tworzymy klasę
AdresGorskiAdapter
która rozszerza klasęAdresGorski
- Tworzymy klasę
Smok
, która sprawdza prawidłowość adresu i używa do tego odpowiedniej klasy - Napisać klasę
Main
, aby sprawdzić działanie adaptera.
Klasy
Klasa Smok
package adapter.composition; class Smok { private static final String ADRES_GORSKI = "AG"; private static final String ADRES_NIZINNY = "AN"; private String name; private final String prowincja; private final String miejscowosc; private String gora; private final String typ; private int nrJaskini; public Smok(String name, String prowincja, String systemGorski, String gora, String typ) { this.name = name; this.prowincja = prowincja; this.miejscowosc = systemGorski; this.gora = gora; this.typ = "AG"; } public Smok(String name, String prowincja, String miejscowosc, int nrJaskini, String typ) { this.name = name; this.prowincja = prowincja; this.miejscowosc = miejscowosc; this.nrJaskini = nrJaskini; this.gora = String.valueOf(nrJaskini); this.typ = "AN"; } public boolean isValidAddress() { if (typ.equals(Smok.ADRES_GORSKI)) { AdresGorski ag = new AdresGorski(); AdresGorskiAdapter ad = new AdresGorskiAdapter(ag); return ad.isValidAddress(prowincja, miejscowosc, nrJaskini); } if (typ.equals(Smok.ADRES_NIZINNY)) { AdresNizinny an = new AdresNizinny(); return an.isValidAddress(prowincja, miejscowosc, nrJaskini); } return true; } public String getGora() { return gora; } public void setGora(String gora) { this.gora = gora; } public String getName() { return name; } public void setName(String name) { this.name = name; } }// end of class
Klasa AdresNizinny
package adapter.composition; class AdresNizinny extends AddressValidator { @Override public boolean isValidAddress(String prowincja, String miejscowosc, int nrJaskini) { if (prowincja.trim().length() != 2) { return false; } if (miejscowosc.trim().length() < 1) { return false; } return nrJaskini >= 1; } }
Klasa AdresGorski
package adapter.composition; class AdresGorski { boolean isValidAddressGorski(String prowincja, String systemGorski, String gora) { if (prowincja.trim().length() != 2) { return false; } if (systemGorski.trim().length() < 1) { return false; } return !gora.trim().equals(""); } }
Klasa AdresGorskiAdapter
package adapter.composition; class AdresGorskiAdapter extends AdresGorski { AdresGorskiAdapter(AdresGorski ad) { } public boolean isValidAddress(String prowincja, String miejscowosc, int nrJaskini) { return isValidAddressGorski(prowincja, miejscowosc, String.valueOf(nrJaskini)); } }
Klasa AddressValidator
package adapter.composition; abstract class AddressValidator { public abstract boolean isValidAddress(String prowincja, String miejscowosc, int nrJaskini); }
Klasa Main
package adapter.composition; class Main { public static void main(String[] args) { Smok smok = new Smok("Vellys", "AG", "Pomiechówek", 7, "AN"); System.out.println(smok.isValidAddress()); Smok smok1 = new Smok("Vollys", "AS", "Zakopane", "Jaskinia", "AG"); System.out.println(smok1.isValidAddress()); } }
Wynik
true true
Inne rozwiązania
We wpisach
Generowanie własnych zdarzeń dziedziczących po AWTEvent oraz Tworzenie klasy adapterowej dla własnych zdarzeń pokazałam inny sposób tworzenia klasy adapterowej.