1 / 16

Decorator

Decorator. Motivační příklad – GUI Toolkit. GUI Toolkit obsahuje komponentu TextView prosté zobrazení textu Chceme instance této komponenty „dekorovat“ přidat posuvník přidat rámeček apod. Hodilo by se přitom: mít k dispozici také původní TextView bez dekorací

selia
Download Presentation

Decorator

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Decorator

  2. Motivační příklad – GUI Toolkit • GUI Toolkit obsahuje komponentu TextView • prosté zobrazení textu • Chceme instance této komponenty „dekorovat“ • přidat posuvník • přidat rámeček • apod. • Hodilo by se přitom: • mít k dispozici také původní TextView • bez dekorací • kombinovat vlastnosti mezi sebou • posuvník + rámeček • přidávat některé vlastnosti vícenásobně • dvojitý rámeček • přidávat/odebírat konkrétní vlastnosti za běhu

  3. Motivační příklad – GUI Toolkit • 1. pokus o řešení: „supertřída“ • obsahuje stavy (flagy) pro všechny možné dekorace • vykreslovací metoda kontroluje přítomnost jednotlivých dekorací • class TextView • { • public: • void Draw() • { • /* Main drawing logic here. */ • if (isBordered) • { • /* Border drawing logic here. */ • } • if (isScrollable) • { • /* Scrollbar drawing logic here. */ • } • } • private: • bool isBordered; // Is TextView bordered? • int borderWidth; // State used only by bordered TextViews. • bool isScrollable; // Is TextView scrollable? • intscrollBarPosition; // State used only by scrollable TextViews. • };

  4. Motivační příklad – GUI Toolkit • 1. pokus o řešení: „supertřída“ • můžeme instancím přidávat/odebírat vlastnosti za běhu  • nemusíme dekorovat vůbec  • můžeme kombinovat vlastnosti  • netřeba rozlišovat mezi obyčejnou a dekorovanou instancí  • nemůžeme jednu vlastnost použít vícekrát  • instance ví, že je dekorována  • silně neflexibilní řešení • nerozšiřitelné bez modifikace TextView

  5. Motivační příklad – GUI Toolkit • 2. pokus o řešení: dědičnost • bázová třída – TextView • odvozené – BorderedTextView, ScrollableTextView, BorderedScrollableTextView • class TextView { • public: • void Draw() { ... } • }; • class BorderedTextView : public TextView { • public: • void Draw() { ... } • }; • class ScrollableTextView : public TextView { • public: • void Draw() { ... } • }; • class BorderedScrollableTextView : public ScrollableTextView { • public: • void Draw() { ... } • };

  6. Motivační příklad – GUI Toolkit • 2. pokus o řešení: dědičnost • statické • nemožno měnit vlastnosti instance za běhu  • pro každou kombinaci vlastností je třeba vytvořit novou třídu • BorderedScrollableBorderedTextView ...  • vede k explozi tříd (n vlastností → 2n tříd)   • podstatně zvyšuje komplexitu systému

  7. Motivační příklad – GUI Toolkit • 3. pokus o řešení: Decorator Společný (abstraktní) předek – def. interface pro kreslení Konkrétní vizuální komponenta Reference na dekorovaný objekt Delegace vykreslování na dekorovaný objekt Abstraktní dekorátor Konkrétní dekorátory vyjma delegace implementují navíc své vlastní vykreslování Konkrétní dekorátor

  8. Motivační příklad – GUI Toolkit • 3. pokus o řešení: Decorator class VisualComponent { public: virtual void Draw() = 0; }; class TextView : public VisualComponent { public: virtual void Draw(){ ... } }; class Decorator : public VisualComponent { public: Decorator(VisualComponent * vc) { _vc = vc; } virtual void Draw() { _vc->Draw(); } private: VisualComponent* _vc; }; class ScrollDecorator : public Decorator { public: ScrollDecorator(VisualComponent *vc) : Decorator(vc){} virtual void Draw() { Decorator::Draw();// draw component DrawScrollbar(); // draw scrollbar } void ScrollTo(int pos) { scroll_position = pos; } private: int scroll_position; }; class BorderDecorator : public Decorator { ... };

  9. Motivační příklad – GUI Toolkit • 3. pokus o řešení: Decorator • dekorátory přidávají jednotlivé vlastnosti (dekorace) • můžeme instancím přidávat/odebírat vlastnosti za běhu  • máme k dispozici i obyčejný TextView • dekorace jsou navzájem nezávislé  • lze je libovolně kombinovat  • lze je používat i vícekrát  • je to transparentní  • z hlediska klienta není rozdíl mezi obyčejným a dekorovaným TextView • TextView o dekoracích vůbec neví VisualComponent * visualComponent= new BorderDecorator( new ScrollDecorator( new TextView())); visualComponent->Draw();

  10. Decorator – struktura a účastníci • Účastníci: • Component – def. rozhraní pro objekty, které je možné dynamicky rozšiřovat • ConcreteComponent – def. objekt, který je možné dynamicky rozšířit • Decorator – def. rozhraní pro všechny dekorátory • obsahuje refenci na objekt, který dekoruje • všechna volání deleguje na dekorovaný objekt • ConcreteDecorator – přidává dodatečné chování komponentě

  11. Decorator – o čem to je • Rozšiřuje objekty o dodatečné chování • rozšiřuje konkrétní objekty, ne třídy • rozšiřuje objekt dynamicky, tj. za běhu • Upřednostňuje kompozici objektů před dědičností • Delegace volání na dekorovaný objekt + vlastní přidaná funkcionalita • vlastní přidané chování může být před i za delegovaným voláním • Použití typicky pomocí řetězení konstruktorů: Component component = new ConcreteDecoratorA( new ConcreteDecoratorB( new ConcreteComponent(...))); component.Operation();

  12. Decorator – výhody a nevýhody • Výhody • vyšší flexibilita pro přidávání funkcionality než při statickém dědění • vlastnosti lze přidávat/odebírat za běhu aplikace • několikanásobné použití stejné dekorace • transparentnost • „pay-as-you-go“ • není třeba předvídat všechny potřeby klienta • jednoduché inkrementální přidávání funkcionality • Nevýhody • komponenta a její dekorovaná verze nejsou identické • dekorátor se chová jako transparentní zapouzdření • při použití dekorátorů nespoléhat na identitu objektů! • mnoho podobných (malých) objektů • potenciálně horší orientace v kódu

  13. Decorator – implementace • Rozhraní dekorátoru musí být shodné s rozhraním dekorovaného objektu • dědění od společného předka nebo implementace společného interface • Abstraktní dekorátor lze vynechat • za předpokladu, že potřebujeme přidat pouze jediné rozšíření • často v případě, kdy potřebujeme rozšířit existující kód • delegování na komponentu se pak děje přímo v tomto jediném dekorátoru • Společný předek (Component) by měl zůstat odlehčený • definice rozhraní, nikoli uložení dat • jinak hrozí, že dekorátory budou příliš těžkotonážní • Dobré zvážit, zda měnit povrch objektu, či jeho vnitřnosti • návrhový vzor Strategy

  14. Reálně využívané Decoratory • Grafické toolkity • X Windows System • Java Swing • System.Windows.Controls • Čtení vstupu, zapisování výstupu • System.IO.Stream • java.io Component ConcreteComponent Decorator DataInputStreamdis = new DataInputStream( new GzipInputStream( new BufferedInputStream( new FileInputStream("file.gz")))); dis.Read(...); ConcreteDecorator

  15. Související vzory • Adapter • Decorator mění pouze chování objektu, ne jeho rozhraní • Adapter dá objektu zcela nové rozhraní • Composite • Decorator lze technicky vnímat jak zdegenerovaný Composite • s jedinou komponentou • Decorator přidává dodatečné chování • není určen pro agregaci objektů • Strategy • Decorator umožňuje měnit skin (povrch, kůži...) objektu • v zásadě obaluje nějaký objekt a mění při tom jeho chování • zatímco Strategy umožňuje měnit „vnitřnosti“ (guts) objektu • komponenta ve Strategy ví o možných extenzích, u Decoratoru nikoli:

  16. Děkuji za pozornost! Q & A

More Related