Zielony Smok - logo witryny

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)

  1. Stworzyć interface AddresValidator dopasowany do klasy AdresNizinny
  2. Zaimplementować ten interfejs w klasie AdresNizinny
  3. Stworzyć klasę AdresGorski
  4. Stworzyć klasę AdresGorskiAdapter pozwalającą na walidację adresu AdresGorski tak jakby on był
    typu AdresNizinny. Klasa AdresGorskiAdapter rozszerza klasę
    AdresGorski i implementuje interface AdresValidator
  5. Napisać klasę Smok pozwalającą wpisywać i walidować adresy niezależnie
    od ich typu zapisania. W metoda getValidator w przypadku klasy AdresGorski
    zwraca Adapter! Gdyby w klasach AdresGorski i AdresNizinny wszystkie
    pola były typu String to klasa Smok miałaby jeden konstruktor.
  6. 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)

  1. Tworzymy klasę abstrakcyjną AdresWalidator
  2. Klasa AdresNizinny jest implementacją tej klasy
  3. Tworzymy klasę AdresGorski
  4. Tworzymy klasę AdresGorskiAdapter która rozszerza klasę AdresGorski
  5. Tworzymy klasę Smok, która sprawdza prawidłowość adresu i używa do tego odpowiedniej klasy
  6. 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.