G
Gregory
I recently reviewed the decorator pattern in the GOF book and noticed a
problem.
Let look at the example given in the book. For simplicity I removed
intermediate Decorator class.
// Interface class
class VisualComponent
{
public:
VisualComponent();
virtual void Draw();
virtual void Resize();
// ...
};
// Concrete component
class TextView: public VisualComponent
{
public:
TextView(...);
virtual void Draw();
virtual void Resize();
// ...
private:
// ...
};
// Decorator
class BorderDecorator : public VisualComponent
{
public:
Decorator(VisualComponent*);
virtual void Draw();
virtual void Resize();
// ...
private:
void DrawBorder ( int ) ;
private:
VisualComponent* _component;
int _width;
};
void BorderDecorator :: Draw ()
{
_component->Draw ( ) ;
DrawBorder (_width) ;
}
void BorderDecorator: :Resize ()
{
_component->Resize ( ) ;
}
The BorderDecorator class stores pointer to the VisualComponent object
and delegates
execution of all its methods to the same method of this object. However
for the Draw() method
additional functionality (drawing window border) is added. Good so far.
But what happens if the concrete component TextView implements its
methods using
the decorated Draw() method. Lets say:
void TextView::Resize ()
{
// Do some resing stuff
.....
// Re-draw the window
Draw();
}
Then when invoking BorderDecorator::Resize() method no border will be
drawn for the
TextView window. This breaks our original intention to draw border
every time the TextView is
displayed.
In general it seems that decorator pattern does not behave well when
the decorated
public functionality (method Draw() above) is used in some Concrete
component methods (Resize()).
Does anybody know any solution to the described decorator problem ?
Gregory
problem.
Let look at the example given in the book. For simplicity I removed
intermediate Decorator class.
// Interface class
class VisualComponent
{
public:
VisualComponent();
virtual void Draw();
virtual void Resize();
// ...
};
// Concrete component
class TextView: public VisualComponent
{
public:
TextView(...);
virtual void Draw();
virtual void Resize();
// ...
private:
// ...
};
// Decorator
class BorderDecorator : public VisualComponent
{
public:
Decorator(VisualComponent*);
virtual void Draw();
virtual void Resize();
// ...
private:
void DrawBorder ( int ) ;
private:
VisualComponent* _component;
int _width;
};
void BorderDecorator :: Draw ()
{
_component->Draw ( ) ;
DrawBorder (_width) ;
}
void BorderDecorator: :Resize ()
{
_component->Resize ( ) ;
}
The BorderDecorator class stores pointer to the VisualComponent object
and delegates
execution of all its methods to the same method of this object. However
for the Draw() method
additional functionality (drawing window border) is added. Good so far.
But what happens if the concrete component TextView implements its
methods using
the decorated Draw() method. Lets say:
void TextView::Resize ()
{
// Do some resing stuff
.....
// Re-draw the window
Draw();
}
Then when invoking BorderDecorator::Resize() method no border will be
drawn for the
TextView window. This breaks our original intention to draw border
every time the TextView is
displayed.
In general it seems that decorator pattern does not behave well when
the decorated
public functionality (method Draw() above) is used in some Concrete
component methods (Resize()).
Does anybody know any solution to the described decorator problem ?
Gregory