Decorator 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.

Download Report

Transcript Decorator 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.

Decorator
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
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


kombinovat vlastnosti mezi sebou


posuvník + rámeček
přidávat některé vlastnosti vícenásobně


bez dekorací
dvojitý rámeček
přidávat/odebírat konkrétní vlastnosti za běhu
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
private
private
private
}
bool isBordered;
int borderWidth;
bool isScrollable;
int scrollBarPosition;
//
//
//
//
Is TextView bordered?
Used only by bordered TextViews.
Is TextView scrollable?
Used only by scrollable TextViews.
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
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 extends TextView {
public void Draw() { ... }
}
class ScrollableTextView extends TextView {
public void Draw() { ... }
}
class BorderedScrollableTextView extends ScrollableTextView {
public void Draw() { ... }
}
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
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átor
Konkrétní dekorátory vyjma
delegace implementují navíc
své vlastní vykreslování
Motivační příklad – GUI Toolkit

3. pokus o řešení: Decorator
public interface VisualComponent
{
public void Draw();
}
class TextView implements VisualComponent
{
public void Draw() {
// draw window
}
}
abstract class Decorator implements
VisualComponent
{
protected VisualComponent vc;
// component being decorated
public Decorator(VisualComponent vc) {
this.vc = vc;
}
public void Draw() {
vc.draw(); //delegation
}
}
class ScrollDecorator extends Decorator {
public ScrollDecorator(VisualComponent
vc) {
super(vc);
}
@Override
public void Draw() {
super.Draw();
drawScrollBar();
}
// draw component
// draw scrollbar
private void drawScrollBar() {...}
private int scroll_position;
public void ScrollTo(int pos)
{
scroll_position = pos;
}
}
class BorderDecorator extends Decorator {
...
}
Motivační příklad – GUI Toolkit

3. pokus o řešení: Decorator
VisualComponent window =
new BorderDecorator(
new ScrollDecorator(
new TextView()));
window.Draw();
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í
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ě
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
Decorator – implementace

Použití typicky pomocí řetězení konstruktorů:
Component c =
new ConcreteDecoratorA(
new ConcreteDecoratorB(
new ConcreteComponent(...)));
c.Operation();

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
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
Decorator
ConcreteComponent
DataInputStream dis =
new DataInputStream(
new GzipInputStream(
new BufferedInputStream(
new FileInputStream("file.gz"))));
dis.Read(...);
ConcreteDecorator
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


Decorator přidává dodatečné chování


s jedinou komponentou
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: