Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Visitor. Visitor - motivace Existující struktura typů Unit Character Main Hero Monster Environment Wall Magic Wall Stone Tree Mnoho nezávislých operací.

Podobné prezentace


Prezentace na téma: "Visitor. Visitor - motivace Existující struktura typů Unit Character Main Hero Monster Environment Wall Magic Wall Stone Tree Mnoho nezávislých operací."— Transkript prezentace:

1 Visitor

2 Visitor - motivace Existující struktura typů Unit Character Main Hero Monster Environment Wall Magic Wall Stone Tree Mnoho nezávislých operací Draw Collision Animation

3 Visitor - motivace Každá dvojice typ a operace má jiný kód Main Hero, Draw Wall, Collision Stone, Collision... Implementace operace v jednom modulu DrawHero DrawWall DrawStone... Předpokládáme stabilní struktura typů se společným předkem přibývající operace

4 Visitor – Double Dispatch Intermezzo Single Dispatch  C++, C#, Java  Jméno funkce + odkaz na objekt  Podpora v jazyce pomocí virtuálních funkcí Double Dispatch  CLOS, Haskell, Dylan  Jméno funkce + odkaz na objekt 1 + odkaz na objekt 2  příklad: výpočet obsahu průniku dvou geometrických obrazců  Možné řešení:  pomocí vzoru Visitor  hrubou silou  šablony + typelisty  type_info + std::map ...

5 Visitor - motivace Možné řešení bez visitoru - operace v třídách Výhody  jednoduché  intuitivní Nevýhody  pracné přidávání metod  funkčnost rozházená po třídách  nezachovává se stav MagicWall draw() collision() animation()... Environment draw() collision() animation()... Wall draw() collision() animation()... Stone draw() collision() animation()... …… Client

6 Visitor - motivace Možné řešení bez visitoru - špagetový kód Výhody  kód na jednom místě Nevýhody  nepřehledný, opakující se kód  mnoho switch / if-else-if bloků pomalé, snadné zapomenout na nějaký typ void printStatistics(List elements){ foreach (Unit e in elements) { if (e is Wall) { //... } else if (e is MagicWall) { //... } else if (e is Stone) { //... }

7 Visitor - motivace Řešení s použitím Visitoru Environment accept(Visitor v) Wall accept(Visitor v) MagicWall accept(Visitor v) Stone accept(Visitor v) v.visitMagicWall(this);v.visitStone(this); Object structure (Traverser) v.visitWall(this); Visitor visitWall(Wall e) visitMagicWall(MagicWall e) visitStone(Stone e) DrawVisitor visitWall(Wall e) visitMagicWall(MagicWall e) visitStone(Stone e) CollisionVisitor visitWall(Wall e) visitMagicWall(MagicWall e) visitStone(Stone e) Potomci Visitora jednoduše přidávají další operace bez nutnosti změny v typech struktury typů. Každý uzel v metodě accept zavolá Visitora „na návštěvu“

8 Visitor Visitor obecně Visitor visitA(ElementA) visitB(ElementB) Visitor1 visitA(ElementA) visitB(ElementB) Visitor2 visitA(ElementA) visitB(ElementB) AbstractElement accept(Visitor) ElementA accept(Visitor) ElementB accept(Visitor) v.visitA(this);v.visitB(this); Object structure (Traverser) Client

9 Visitor - účastníci Přehled účastníků  Visitor interface (nebo abstraktní třída), který musí implementovat konkrétní Visitory definuje metody visit pro všechny typy elementů  může využívat i overloading funkcí: Visit( ElementA& ); Visit( ElementB& );  Visitor1, Visitor2 konkrétní Visitory (implementují rozhraní Visitor) přidávají novou funkcionalitu do existující struktury  AbstractElement interface (nebo abstraktní třída) pro typy, které mohou být navštíveny Visitorem definuje abstraktní metodu accept  ElementA, ElementB konkrétní elementy odvozené od AbstractElement implementují metodu accept (uvnitř které pozve předaného Visitora na návštěvu)  Object structure (traverser) umí procházet strukturu elementů na každém elementu zavolá metodu accept

10 Visitor - vlastnosti Výhody  snadno přidám novou operaci na třídě stačí napsat nového Visitora není třeba měnit objekty hierarchie Visitory mohou být implementovány jako zásuvné moduly  zapouzdření souvisejících operací Visitor skrývá specifika algoritmu  udržování kontextu při průchodu strukturou objektů uvnitř Visitoru Visitor může mít vnitřní stav (data)  nemusí se předávat parametrem, nebo v globálních hodnotách  vnitřní stav může ovlivnit prováděné operace

11 Visitor - důsledky a souvislosti Nevýhody  přidání nového typu objektu většinou znamená úpravu všech Visitorů nasazení při častěji měnící se struktuře je nevhodné  porušení zapouzdření objektů, nad nimiž se operuje Visitor může potřebovat pracovat s interním stavem  obtížné zavedení do hotového kódu  složitějsí kód explicitní získávání návratové hodnoty

12 Visitor – sekvenční diagram Sekvenční diagram

13 Visitor - procházení struktury Jakým způsobem lze procházet strukturu objektů visitorem? Kde bude kód umístěn:  klient více práce pro klienta klient má možnost plně řídit, koho Visitor navštíví  struktura rekurzivní volání metody accept na potomky při použití vzoru Composite  Iterator nelze použít, pokud objekty nemají společného předka kód na procházení je na jediném místě  Visitor elementy struktury nemusí mít společného předka komplexnější algoritmy průchodu strukturou duplikace kódu na procházení v každém Visitoru

14 Visitor – implementace C# interface IElement { void Accept(IVisitor visitor); } interface IVisitor { void Visit(IElement element); void Visit(Wall binary); void Visit(Stone value); void Visit(Map value); } vše zachytávající funkce společný interface class Wall:IElement { public readonly int Number;... public void Accept(IVisitor visitor) { visitor.Visit(this); } class Wall:IElement { public readonly int Number;... public void Accept(IVisitor visitor) { visitor.Visit(this); } accept na jednoduchém objektu class Map: IElement { public readonly char Operator; public readonly List staticObjects; public readonly List characters;... public void Accept(IVisitor visitor) { foreach(var e in this.staticObjects) { e.Accept(visitor); } foreach(var e in this.staticObjects) { e.Accept(visitor); } visitor.Visit(this); } class Map: IElement { public readonly char Operator; public readonly List staticObjects; public readonly List characters;... public void Accept(IVisitor visitor) { foreach(var e in this.staticObjects) { e.Accept(visitor); } foreach(var e in this.staticObjects) { e.Accept(visitor); } visitor.Visit(this); } accept na složeném objektu

15 Visitor – implementace C# class CollisionVisitor : IVisitor { private Hero hero; // whether hero collides private bool status; public void Visit(IElement element) { if(!(hero.x + hero.width < element.x || hero.x > element.x + element.width) || !(hero.y + hero.height < element.y || hero.y > element.y + element.height)){ status = false; } }... } class DrawVisitor : IVisitor { private Dictionary bitmaps; public void Visit(IElement element) { throw new Exception("Unknown object"); } public void Visit(Wall element) { if(!bitmaps.ContainsKey(element)) bitmaps[element] = LoadWallBitmap(); Window.Draw(this.bitmaps[element]); } public void Visit(Stone value) { if(!bitmaps.ContainsKey(element)) bitmaps[element] = LoadStoneBitmap() Window.Draw(this.bitmaps[element]); }... }

16 interface IVisitor { void Visit(IElement element); void Visit(Wall binary); void Visit(Stone value); void Visit(Map value); void Visit(BabaYagaMonster value); } Visitor – problém s rozšiřitelností Chtěli bychom přidat BabaYagaMonster

17 class DrawVisitor : IVisitor { private Dictionary bitmaps; public void Visit(IElement element) { throw new Exception("Unknown object"); } public void Visit(Wall element) { if(!bitmaps.ContainsKey(element)) bitmaps[element] = LoadWallBitmap(); Window.Draw(this.bitmaps[element]); } public void Visit(Stone value) { if(!bitmaps.ContainsKey(element)) bitmaps[element] = LoadStoneBitmap() Window.Draw(this.bitmaps[element]); } public void Visit(BabaYagaMonster value) { if(!bitmaps.ContainsKey(element)) bitmaps[element] = LoadBabaYagaBitmap() Window.Draw(this.bitmaps[element]); }... } interface IVisitor { void Visit(IElement element); void Visit(Wall binary); void Visit(Stone value); void Visit(Map value); void Visit(BabaYagaMonster value); } Visitor – problém s rozšiřitelností Chtěli bychom přidat BabaYagaMonster class CollisionVisitor : IVisitor { private Hero hero; // whether hero collides private bool status; public void Visit(IElement element) { if(!(hero.x + hero.width < element.x || hero.x > element.x + element.width) || !(hero.y + hero.height < element.y || hero.y > element.y + element.height)){ status = false; } public void Visit(BabaYagaMonster value) { // No implementatation }... }

18 Visitor – Double dispatch C#... IVisitor visitor = new ConcreteVisitor(); foreach(IElement el in elements) { visitor.Visit(el); } class ConcreteVisitor:IVisitor { void Visit(IElement w){... } void Visit(UnaryOperator w){... } interface IVisitor { void Visit(IElement w); } Řešení ?

19 Visitor – Double dispatch C#... IVisitor visitor = new ConcreteVisitor(); foreach(IElement el in elements) { visitor.Visit(el); } class ConcreteVisitor:IVisitor { void Visit(IElement w){... } void Visit(UnaryOperator w){... } interface IVisitor { void Visit(IElement w); } Řešení ? K výběru funkce dochází již za překladu!

20 Visitor – Double dispatch C#... IVisitor visitor = new ConcreteVisitor(); dynamic dispatchedVisitor=visitor; foreach(IElement el in elements) { dispatchedVisitor.Visit((dynamic) el); } class ConcreteVisitor:IVisitor { void Visit(IElement w){... } void Visit(UnaryOperator w){... } interface IVisitor { void Visit(IElement w); } Řešení !

21 Visitor – Double dispatch C#... IVisitor visitor = new ConcreteVisitor(); dynamic dispatchedVisitor=visitor; foreach(IElement el in elements) { dispatchedVisitor.Visit((dynamic) el); } class ConcreteVisitor:IVisitor { void Visit(IElement w){... } void Visit(UnaryOperator w){... } interface IVisitor { void Visit(IElement w); } Ale... Dynamické typování je výrazně pomalejší

22 Visitor - Shrnutí Používáme když  máme stabilní strukturu typů  chceme přidávat nezávislé funkce nad typy struktury Není vhodné když struktura typů není stabilní  přidání nového typu je pracné Výhody  přehledný kód  rozšiřitelnost funkcí nad typy  zapouzdření kontextu dané funkce Visitor částečně nahrazuje chybějící podporu Double Dispatch v jazycích jako jsou C++, C#, Java Obecná implementeace techniky Multi Dispatch se nazývá Multimethods

23 Visitor - použití v praxi Příklady  XML parsery (např. SAX) parser.parse(file, handler) startElement() endElement() character()  Stromové struktury visitNode visitLeaf  Překladače operace nad syntaktickým stromem


Stáhnout ppt "Visitor. Visitor - motivace Existující struktura typů Unit Character Main Hero Monster Environment Wall Magic Wall Stone Tree Mnoho nezávislých operací."

Podobné prezentace


Reklamy Google