Zastosowanie
Adapter
(ang. Adapter
) (wzorzec strukturalny) umożliwia współpracę dwóch klas o niekompatybilnych interfejsach dzięki przekształceniu interfejsu jednej klasy na zrozumiałą postać dla drugiej. Adapter
zwany inaczej Wrapper
jest swego rodzaju przejściówką między dwoma bytami. Wyróżnia się dwa warianty klasycznej postaci tego wzorca Adapter Klasowy
oraz Adapter Obiektowy
. Wybór rodzaju Adaptera
w zależności od warunków może być dowolny lub podyktowany ograniczeniami. W sytuacji gdy nie można rozszerzyć klasy adaptowanej używany jest Adapter Obiektowy
, natomiast gdy klasa adaptowana jest abstrakcyjna stosuje się Adapter Klasowy
. Ze względu zagrożenia jakie niesie ze sobą używanie Adaptera Klasowego
w większości sytuacji stosuje się Adapter Obiektowy
. Ponadto mówi się o Adapterze Dwukierunkowym
, w którym translacja zachodzi w obie strony, tzn. klient jest jest także klasą adapatowaną. Taki mechanizm może posłużyć np. do konwersji typów.
Ograniczenia
Przy tworzeniu Adaptera
należy mieć na uwadzę, że wraz ze wzrostem niekompatybilności maleje wydajność co może stanowić problem w niektórych aplikacjach. Adapter Obiektowy
nie ma możliwości przeładowania metod klasy adaptowanej, natomiast Adapter Klasowy
nie pozwala na adaptowanie podklas klasy adaptowanej. Adapter Klasowy
ściśle wiąże klienta z klasą adaptowaną co w przypadku rozrostu systemu czy zmiany wymagań zmniejsza reużywalność kodu.
Użycie
Stosowany jest głównie tam, gdzie wykorzystanie istniejącej klasy w celu komunikacji z inną klasą jest niemożliwe ze względu na niekompatybilność interfejsu. Ponadto Adapter
używany jest w sytuacjach, gdy tworzona klasa będzie współpracować z klasami o nieokreślonych interfejsach.
Implementacja
Adapter Klasowy
dziedziczy po klasie adaptowanej Adaptee
oraz implementuje klase klienta Client
. Adapter Obiektowy
implementuje klase klienta Client
oraz zawiera instancję klasy adaptowanej Adaptee
.
Klasa Client
oraz Adaptee
są niekompatybilne co przedstawia poniższy listing.
Aby możliwa była komunikacja należy między nimi wprowadzić Adapter
. Poniższy listing przedstawia implementacje wzorca w dwóch wariantach.
Tak przygotowane adaptery umożliwią wywołanie metod klasy adaptowanej Adaptee
z poziomu klasy Client
co przedstawia poniższy listing.
Przykład
Komunikator Messenger
umożliwia wysyłanie wiadomości tekstowych oraz plików między rozmówcami wykorzystując w tym celu wewnętrzną biblioteke protokołu sieciowego. Ponadto aplikacja pozwala na zmianę statusu. Poniższy listing przedstawia implementacje komunikatora Messenger
wraz z jego protokołem MessageProtocol
.
W pewnym momencie cyklu życia projektu zachodzi potrzeba wymiany protokołu sieciowego MessageProtocol
na bardziej wydajną biblioteke zewnętrzną ExternalMessageProtocol
. Dodatkowo każda operacja ma wysyłać dane do analityki. Ze względu na rozmiar projektu nie wchodzi w grę zmiana typu instancji protokołu oraz wywołań metod we wszystkich wystąpieniach obiektu klasy Messenger
. Rozwiązaniem tego problemu jest zastosowanie Adaptera
, którego implementacja przedstawiona jest poniżej.
Aby skorzystać z nowego rozwiązania wystarczy przekazać referencje Adaptera
do aplikacji w następujący sposób.
Biblioteki
Adapter
jest standardowym elementem biblioteki Android
. Jego celem jest dostarczenie danych do widoku kolekcji AdaperView
, a także stworzenie widoków View
dla każdego elementu ze zbioru danych. Metody asList
klasy Arrays
oraz list
klasy Collections
są przykładem implementacji wzorca w standardowym pakiecie Java
.