Adapter 1 1 1 1
Adapter – motivace 2 2 2 2
Adapter – pojem Součástka navržená k propojení dvou „nekompatibilních“ zařízení Definice slova podle Cambridge Advanced Learner's Dictionary: Adapter (také adaptor) A type of plug which makes it possible to connect two or more pieces of equipment to the same electrical supply Druh zástrčky, která umožňuje připojení dvou nebo více druhů zařízení do téhož elektrického napájení A device which is used to connect two pieces of equipment Zařízení používané pro propojení dvou jiných zařízení 3 3 3 3
Adapter – návrhový vzor Také „Wrapper“ Strukturální návrhový vzor Propojení již existujících tříd s nekompatibilním rozhraním Bez jejich změny Asymetrické – jednu třídu „připojujeme k druhé“ 4 4 4 4
Adapter – účastníci Target Client Adapter (definuje rozhraní vyžadované Clientem) Client (pro něj přizpůsobujeme) Adapter (přizpůsobuje Adaptee na Target rozhraní) Adaptee (implementuje operace, které chce Client využívat) 5 5 5 5
Adapter – účastníci – shrnutí Client Pro něj přizpůsobujeme Využívá rozhraní Target Target Definuje rozhraní, které vyžaduje Client Obvykle abstraktní třída / interface Adaptee (= adaptovaný, přizpůsobovaný) Poskytuje požadované operace Jiné rozhraní než Target Často převzatý kód, který nelze měnit Adapter Přizpůsobuje Adaptee na interface Target 6 6 6 6
Inherited implementation Adapter – dvě možnosti zapojení Object Adapter Class Adapter Composition „has a“ Client Target Request() Adapter adaptee -> SpecificRequest() Adaptee SpecificRequest() Public inheritance „is a“ Private inheritance „is implemented in terms of“ Client Target Request() Adapter SpecificRequest() Adaptee Public inheritance „is a“ Inherited implementation 7 7 7
Adapter – Drawing App - příklad 8 8 8 8
Adapter – příklad Target Shape definuje cílové rozhraní class Shape { virtual void BoundingBox( Point& bottomLeft, Point& topRight ) const; virtual Manipulator* CreateManipulator() const; }; Adaptee TextView implementuje některé metody, ale v jiném rozhraní class TextView { void GetOrigin( Coord& x, Coord& y ); void GetExtent( Coord& width, Coord& height ); virtual bool IsEmpty() const; }; 9 9 9 9
Object Adapter 10 10 10 10
Object Adapter – příklad Client pracuje s potomky Shape Target definuje cílové rozhraní Adaptee má vlastní rozhraní Composition „has a“ DrawingApp Shape BoundingBox() TextShape text -> GetExtent() TextView GetExtent() Public inheritance „is a“ Adapter přizpůsobuje TextView na interface třídy Shape 11 11 11 11
Object Adapter TextShape veřejně dědí od Object Adapter – příklad Object Adapter TextShape veřejně dědí od Targetu Shape Object Adapter TextShape class TextShape: public Shape { public: TextShape(TextView* t); virtual void BoundingBox(Point& bottomLeft, Point& topRight) const; virtual bool IsEmpty() const; virtual Manipulator* CreateManipulator(); private: TextView* text; }; Adaptee TextView je privátním členem Adapteru TextShape 12 12 12
konstruktor vyžaduje již existující instanci Adaptee Object Adapter – příklad Object Adapter TextShape – implementace metod TextShape::TextShape( TextView* t ) { text = t; } void TextShape::BoundingBox( Point& bottomLeft, Point& topRight ) const Coord bottom, left, width, height; text -> GetOrigin( bottom, left ); text -> GetExtent( width, height ); topRight = Point( bottom + height, left + width ); bottomLeft = Point( bottom, left ); bool TextShape::IsEmpty() const return text->IsEmpty(); Manipulator* TextShape::CreateManipulator() const return new TextManipulator( this ); konstruktor vyžaduje již existující instanci Adaptee 13 13 13
Object Adapter – vlastnosti Využívá kompozici Adaptee je private datovou položkou Adapter Možnost runtime změny Může vzniknout jako wrapper kolem již existující instance Adaptee Příklad – TextShape::TextShape( TextView* t ) Může adaptovat všechny potomky Adaptee Příklad – libovolný potomek TextView Nemá přístup k protected položkám samotného Adaptee Nelze předefinovat položky Adaptee Nepřímo – podtřída Adaptee, předefinovat a použít v Adapteru místo Adaptee 14 14 14
Class Adapter 15 15 15 15
Inherited implementation Class Adapter – příklad Private inheritance „is implemented in terms of“ DrawingApp Shape BoundingBox() TextShape GetExtent() TextView Public inheritance „is a“ Inherited implementation Adapter dědí od Targetu i od Adaptee Adapter může při implementaci Targetu přímo volat metody Adaptee 16 16 16 16
Vícenásobná dědičnost Class Adapter – příklad Class Adapter TextShape Vícenásobná dědičnost public od Target private od Adaptee class TextShape: public Shape, private TextView { public: TextShape(); virtual void BoundingBox( Point& bottomLeft, Point& topRight ) const; virtual bool IsEmpty() const; virtual Manipulator* CreateManipulator() }; 17 17 17 17
Class Adapter – příklad Class Adapter TextShape – implementace metod void BoundingBox( Point& bottomLeft, Point& topRight ) const { Coord bottom, left, width, height; GetOrigin( bottom, left ); GetExtent( width, height ); topRight = Point( bottom + height, left + width ); bottomLeft = Point( bottom, left ); } bool TextShape::IsEmpty() const return TextView::IsEmpty(); Manipulator* TextShape::CreateManipulator() const return new TextManipulator( this ); Přímé volání metody předka Přímé volání metody předka Přímé volání metody předka 18 18 18 18
Class Adapter – vlastnosti Není indirekce při delegaci metod Využívá vícenásobnou dědičnost Přístup k protected položkám Adaptee, lze předefinovat Vícenásobnou dědičnost mnoho jazyků nemá Ale lze dědit od více rozhraní Pro konkrétní Adaptee musíme překopírovat položky 19 19 19
Poznámky k implementaci Kolik práce musí odvést samotný Adapter? Jednoduchá konverze mezi různě pojmenovanými metodami Operace nepodporovaná Adaptee – logika pro zpracování Někdy implementuje Adapter bez pomoci Adaptee Adapter nemusí nutně adaptovat pouze jednu třídu bool TextShape::IsEmpty() const { return TextView::IsEmpty(); } Manipulator* TextShape::CreateManipulator() const { return new TextManipulator(this); } 20 20 20
Některé další variace implementace Two-way Adapter Zaměnitelnost Adapteru za objekty Adaptee Chová se jako Target i Adaptee Typická implementace pomocí vícenásobné public dědičnosti Pluggable Adapter Do této chvíle – jeden Client, jeden Adaptee Mnoho Adapterů pro mnoho adaptovaných tříd 21 21 21
Pluggable Adapter – příklad TreeDisplay Vykreslení stromové struktury Různá reprezentace zdroje dat Jednotné rozhraní pro adaptaci všech reprezentací Minimální – „narrow interface“ Implementace Abstraktní metody Delegát 22 22 22 22
Pluggable Adapter – Abstraktní metody Narrow interface součástí TreeDisplay – abstraktní metody Výchozí implementace zobrazení stromu Potomci implementují narrow interface 23 23 23 23
Pluggable Adapter – Delegát Narrow interface v samostatné třídě/rozhraní Delegát Kompozice Potomci implementují narrow interface Přístup k narrow interface přes delegáta 24 24 24 24
Pluggable Adapter – Delegát class Person //Adaptee1 {public static void SayHey() { Console.WriteLine("Hey!"); }} class Subwoofer //Adaptee2 {public static void Blast() { Console.WriteLine("Woof!"); }} class Adapter { public Action MakeSound { get; private set;} // "pluggable" adapter public Adapter(Action makeSoundAction) { MakeSound = makeSoundAction; } } class SoundMaker //Client { static void Main(string[] args) { (new Adapter(Person.SayHey)).MakeSound(); (new Adapter(Subwoofer.Blast)).MakeSound(); } } 25 25 25
Pluggable Adapter – vlastnosti Abstraktní metody Client je zároveň Target, dědí se přímo od něj Propojení s Adaptee vhodné pouze přes kompozici – object adapter Target není pouze interface – nutná vícenásobná dědičnost Delegát Oddělení narrow interface do delegované třídy Přístup k metodám přes ukazatel Ukazatel zpátky na Clienta Možný object i class adapter Dva objekty – Client a Adapter 26 26 26
Adapter – použití Kdy použít Známá použití Použití existující třídy s nekompatibilním rozhraním Vytváření znovupoužitelné třídy, která používá třídy s potenciálně nekompatibilním rozhraním Známá použití C# – ADO.NET DataAdapter – dotazy nad daty nezávisle na zdroji dat Využití v DataSet Java I/O StringBufferInputStream – adaptuje StringBuffer jako InputStream Pluggable Adapter ve Swingu javax.swing.tree.TreeModel – rozhraní pro zobrazení komponentou JTree 27 27 27 27
Adapter – související NV Bridge Oddělení rozhraní od implementace Nemění rozhraní Využití v době návrhu Adapter – existující rozhraní Decorator Nemění rozhraní objektu Přidání funkcionality Podpora rekurzivní kompozice Facade Zjednodušení rozhraní Proxy Nemění rozhraní – chová se stejně jako objekt sám Skrytí skutečného umístnění objektu (např. objekt na disku, na jiném počítači) 28 28 28 28