Adapter

Situace

V systému existuje nevyhovující třída se zastaralým, nekompatibilním, nebo jinak neuspokojivým rozhraním. Funkcionalita existující třídy má být zachována a pouze s minimálním úsilím převedena pod rozhraní nové. Může se objevit i požadavek, aby se stávající třída již neměnila (a někdy to ani není možné, například při použití knihovny).

Problém

Použití nevyhovující třídy ovlivňuje ta místa v systému, kde je využívána její funkcionalita. Nevyhovující ůže do zbytku systému zanést zbytečný zmatek, který bude navíc umocněn tím, že se zastaralá třída časem odstraní úplně. a navíc se spolu s ním může šířit nedokonalosti, které byly již identifikovány a odstraněny.

Přímá úprava zastaralé třídy by zabrala mnoho času a pokud je již důkladně otestována, není k tomu zpravidla ani vůle. Přesto je ale nutné, aby zbytek systému využíval již rozhraní nové.

Řešení

Nevyhovující třídu lze od zbytku systému odstínit tak, že se celá zapouzdří do třídy nové. Tato třída již implementuje nové rozhraní a poskytuje infrastrukturu pro transformaci požadavků od klienta na příslušné metody zapouzdřené třídy.

Návrhový vzor Adapter se často používá jen jako dočasné řešení do doby, než je nevyhovující třída nahrazena. Toto nahrazení je navíc snadnější, protože zbytek systému je na nové rozhraní připraven. Další častou aplikací tohoto návrhového vzoru je zajištění zpětné kompatibility.

Varianty
  • třídní adaptér – dědí od nevyhovující třídy
  • objektový adaptér – využívá delegaci
UML diagramy

diagram tříd

Související vzory
  • Facade – pro několik tříd vytváří zcela nové rozhraní
  • Iterator – adaptér specializovaný na sekvenční procházení
  • Proxy – má stejné rozhraní jako zapouzdřena třída
Příklad

Následuje jednoduchý příklad implementace tohoto vzoru v programovacím jazyce Java.

Požadovaná funkcionalita

kód v jazyce Java - Zobrazit

  1. /**
  2.  * Rozhraní specifikující požadovanou funkcionalitu.
  3.  *
  4.  * @author Vojtěch Hordějčuk
  5.  */
  6. public interface Target
  7. {
  8.   /**
  9.    * Provede požadavek.
  10.    */
  11.   public void newRequest();
  12. }
Nevyhovující třída

kód v jazyce Java - Zobrazit

  1. /**
  2.  * Vnořená třída, která má zpravidla zastaralé, nekompatibilní, nebo jinak
  3.  * nevyhovujícím rozhraní. Proto k ní bude vytvořen odpovídající adaptér.
  4.  *
  5.  * @author Vojtěch Hordějčuk
  6.  */
  7. public class Adaptee
  8. {
  9.   /**
  10.    * Provede požadavek.
  11.    */
  12.   public void oldRequest()
  13.   {
  14.     // ...
  15.   }
  16. }
Adaptér nevyhovující třídy

kód v jazyce Java - Zobrazit

  1. /**
  2.  * Adaptér, který implementuje funkcionalitu požadovanou rozhraním "Target" a to
  3.  * tak, že přeposílá (deleguje) požadavky třídě vnořené. K tomu může přidat
  4.  * nějakou řídící logiku. Okolí nemusí vědět ani o instanci vnořené třídy, ani o
  5.  * způsobu, jakým se požadavky převádí.
  6.  *
  7.  * @author Vojtěch Hordějčuk
  8.  */
  9. public class Adapter implements Target
  10. {
  11.   /**
  12.    * vnořená třída
  13.    */
  14.   private Adaptee adaptee;
  15.  
  16.   /**
  17.    * Vytvoří novou instanci.
  18.    */
  19.   public Adapter()
  20.   {
  21.     // vytvořit instanci adaptované třídy
  22.     // (instance může být předána i jinak, například parametrem)
  23.  
  24.     this.adaptee = new Adaptee();
  25.   }
  26.  
  27.   @Override
  28.   public void newRequest()
  29.   {
  30.     // v této ukázce se volání pouze jednoduše deleguje
  31.     // (adaptér ale může přidat nějakou řídící logiku navíc)
  32.  
  33.     this.adaptee.oldRequest();
  34.   }
  35. }
Test

kód v jazyce Java - Zobrazit

  1. public static void main(String[] args)
  2. {
  3.   // vytvořit instanci třídy s požadovanou funkcionalitou
  4.  
  5.   Target adapter = new Adapter();
  6.  
  7.   // provést požadavek
  8.  
  9.   adapter.newRequest();
  10. }

Reference