– Cześć, Amigo! Dzisiaj opowiem Ci, czym dokładnie jest «adapter». Mam nadzieję, że po zapoznaniu się z tym tematem, lepiej zrozumiesz strumienie wejściowe/wyjściowe.

Adaptery - 1

Wyobraź sobie, że Twój program używa dwóch frameworków napisanych przez innych programistów/firmy. Oba frameworki są bardzo dobre i wykorzystują zasady OOP: abstrakcję, polimorfizm i enkapsulację. Razem niemal całkowicie załatwiają one wymagania Twojego programu. Pozostaje Ci tylko do wykonania proste zadanie. Musisz przekazać obiekty stworzone przez jeden framework do drugiego. Jednak oba frameworki są zupełnie od siebie różne i „nie wiedzą o sobie nawzajem”, tzn. nie mają żadnych wspólnych klas. Musisz w jakiś sposób przekształcić obiekty jednego frameworku w obiekty drugiego.

To zadanie można pięknie rozwiązać, stosując technikę «adaptera» (wzorzec projektowy):

Kod Java Opis
class MyClass implements Interface2
{
 private Interface1 object;
 MyClass(Interface1 object)
 {
  this.object = object;
 }
// W tym miejscu umieszczamy metody Interface2 
// które wywołują metody Interface1
}
Odzwierciedla to wzorzec projektowy adapter.

Podstawową zasadą jest to, że klasa MyClass konwertuje (dostosowuje) jeden interfejs do drugiego.

– Możesz podać bardziej szczegółowy przykład?

– OK. Powiedzmy, że każdy framework ma swój własny, unikalny interfejs „listy”. Wyglądałoby to mniej więcej tak:

Kod Java Opis
interface AlphaList
{
 void add(int value);
 void insert(int index, int value);
 int get(int index);
 void set(int index, int value);
 int count();
 void remove(int index);
}
Kod z pierwszego frameworku (Alpha)

AlphaList jest jednym z interfejsów, który pozwala na interakcję kodu frameworku z kodem, który korzysta z tego frameworku.

class AlphaListManager
{
 public static AlphaList createList()
 {
  //kod służący do stworzenia obiektu
 }
}
AlphaListManager AlphaListManager jest klasą frameworku. Jego metoda createList tworzy obiekt AlphaList
interface BetaList
{
 int getValue(int index);
 void setValue(int index, int value);
 int getSize();
 void setSize(int newSize);
}
class BetaSaveManager
{
 public static void saveList(BetaList list)
 {
  //kod do zapisania obiektu BetaList
  //do pliku na dysku
 }
}
Kod z drugiego frameworku (Beta).

AlphaList jest jednym z interfejsów, który pozwala na interakcję kodu frameworku z kodem, który korzysta z tego frameworku.

BetaSaveManager jest klasą frameworku. Jego metoda saveList zapisuje obiekt BetaList

class ListAdapter implements BetaList
{
 private AlphaList list;
 ListAdapter(AlphaList list)
 {
  this.list = list;
 }

 int getValue(int index)
 {
  return this.list.get(index);
 }

 void setValue(int index, int value)
 {
  this.list.set(index, value);
 }

 int getSize()
 {
  return this.list.count();
 }

 void setSize(int newSize)
 {
  if (newSize > this.list.count()
  {
   while (this.list.count() < newSize)
  {
   this.list.add(null);
  }
 }
 else if (newSize < this.list.count() {
   while (this.list.count() > newSize)
   {
    list.remove(list.count() - 1);
   }
  }
 }
}
Klasa «Adapter» dokonuje konwersji interfejsu AlphaList na interfejs BetaList

Klasa ListAdapter implementuje interfejs BetaList z drugiego frameworku.

Kiedy ktoś wywołuje te metody, kod klasy «przekazuje» te wywołania do zmiennej list, którą jest AlphaList z pierwszego frameworku.

Obiekt AlphaList jest przekazywany do konstruktora ListAdapter

Metoda setSize działa według następujących zasad: jeżeli konieczne jest zwiększenie rozmiaru listy, dodaje puste pozycje (null). Jeżeli zachodzi konieczność zmniejszenia rozmiaru listy, to usuwa pozycje na końcu.

public static void main(String[] args)
{
 AlphaList listAlpha = AlphaListManager.createList();
 BetaList listBeta = new ListAdapter(listAlpha);
 BetaSaveManager.saveList(listBeta);
}
Przykład, jak można to wykorzystać

– Najbardziej podobał mi się Twój ostatni przykład. Był bardzo treściwy i zrozumiały.