všetky vzory

Adapter

Prekladá rozhranie jednej triedy na rozhranie, ktoré klient očakáva.

// Cudzí kód. Prepísať ho nemôžeme — beží v produkcii roky.class StaraBrana {  odosliPlatbuXml(xml) {    return '<odpoved><stav>OK</stav></odpoved>';  }} // Rozhranie, ktoré klient vie použiť.class Platba {  zaplat(suma) { throw new Error('abstraktná metóda'); }} class BranaAdapter extends Platba {  constructor(brana) {    super();    this.brana = brana;  }   zaplat(suma) {    const xml = '<platba><suma>' + suma + '</suma></platba>';    const odpoved = this.brana.odosliPlatbuXml(xml);    return { stav: odpoved.includes('<stav>OK</stav>') ? 'ok' : 'chyba' };  }} const platba = new BranaAdapter(new StaraBrana());platba.zaplat(25);   // { stav: 'ok' }

Celý priebeh v texte (9 krokov)
  1. Platba je rozhranie, ktoré klient vie použiť. BranaAdapter ho spĺňa — čiara k nemu vedie.
  2. StaraBrana ho nespĺňa a k rozhraniu od nej žiadna čiara nevedie. Prepísať ju nemôžeme — je to cudzí kód, ktorý beží roky. Presne preto tu adaptér je.
  3. Klient zavolá zaplat() — jedinú metódu, ktorú pozná. O starej bráne nevie nič.
  4. Adaptér ďalej zaplat() nevolá. Stará brána takú metódu nemá — vie len odosliPlatbuXml(), takže adaptér volá tú.
  5. Stará brána odpovie po svojom: XML. Tvar odpovede je tu štvorec — takto by ju klient použiť nevedel.
  6. Odpoveď sa vracia adaptéru. Odtiaľto už neletí volanie, ale objekt.
  7. A tu je celý vzor: adaptér preloží odpoveď do tvaru, ktorý klient očakáva. Ten istý údaj, iný tvar.
  8. Takto preloženú ju pošle klientovi.
  9. Klient dostal presne to, čo čakal. Že za tým je XML a dvadsať rokov stará brána, sa nedozvedel — a to je zmysel adaptéra: nezmenil ani jednu z tých dvoch strán, len ich spojil.

Kedy použiť

  • Máš triedu, ktorá robí presne to, čo potrebuješ, ale hovorí iným jazykom — a prepísať ju nemôžeš, lebo je cudzia, stará alebo ju používa aj niekto iný.
  • Chceš, aby bola voľba knižnice alebo dodávateľa lokálna. Keď je celý styk s ňou v adaptéri, výmena za inú je práca na jednom mieste, nie naprieč kódom.
  • Potrebuješ, aby sa niekoľko rôznych zdrojov tvárilo navonok rovnako — tri platobné brány, tri dodávatelia máp, tri formáty importu.
  • Chceš mať čo testovať. Adaptér sa dá nahradiť atrapou a zvyšok kódu o tom nevie.

Pasce

  • Adaptér prekladá rozhranie, nie schopnosti. Keď cieľové rozhranie sľubuje niečo, čo pôvodná trieda nevie, adaptér to buď zamlčí, alebo predstiera — a oboje je horšie než priznať, že sa to nedá.
  • Zamieňa sa s Decoratorom. Obidva držia obalený objekt, ale dekorátor **zachováva** rozhranie a pridáva chovanie, adaptér ho **mení** a chovanie nechá tak.
  • Chyby z druhej strany treba prekladať tiež. Keď adaptér prepustí von výnimku pôvodnej knižnice, jej meno sa rozlezie po kóde, ktorý o nej nemal vedieť — a s ním aj závislosť, ktorú si chcel skryť.
  • Preklad niečo stojí. Pri veľkých dávkach je jeho cena zrazu viditeľná a ľahko sa zabudne, že sa robí pri každom volaní.
  • Cudzia knižnica sa vie zmeniť pod rukami. Adaptér tú zmenu zachytí na jednom mieste, ale nezabráni jej — potrebuje vlastné testy, inak sa o novej verzii dozvieš od používateľov.