473,396 Members | 2,087 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Problem with design pattern decorator

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

Dec 14 '06 #1
3 2169
Gregory wrote:
>
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 ?
The obvious solution would be something like this:

void TextView::resize( VisualComponent& parent )
{
// do resizing stuff
parent.Draw();
}

void BorderDecorator::resize()
{
_component->Resize( *this );
}

To implement such a solution, you either need to be able to modify the
classes in question, or the original designer would have to have
thought of the problem and created the appropriate passthrough
functions. A passthrough function would be needed whenever a concrete
class calls a member-function of the ABC.

Of course, the passthrough function will have to be part of the
VisualComponent interface, probably as a protected pure virtual
member-function.

Dec 15 '06 #2
Daniel T. wrote:
>
The obvious solution would be something like this:

void TextView::resize( VisualComponent& parent )
{
// do resizing stuff
parent.Draw();
}

void BorderDecorator::resize()
{
_component->Resize( *this );
}

To implement such a solution, you either need to be able to modify the
classes in question, or the original designer would have to have
thought of the problem and created the appropriate passthrough
functions. A passthrough function would be needed whenever a concrete
class calls a member-function of the ABC.

Of course, the passthrough function will have to be part of the
VisualComponent interface, probably as a protected pure virtual
member-function.
I forgot to mention... BorderDecorator will of course also need to
implement resize( VisualComponent&). That should be done like this:

void BorderDecorator::resize( VisualComponent& parent )
{
_component->resize( parent );
}

So the top-level decorator has its 'resize()' function called, the
interum decorators have their 'resize(VisualComponent&)' functions
called, the bottom-level object also has it's
'resize(VisualComponent&)' function called, in which it resizes and
calls parent.draw(). 'parent' will be the top-level object.

Dec 15 '06 #3

"""Daniel T. ΠΙΣΑΜ(Α):
"""
Daniel T. wrote:

The obvious solution would be something like this:

void TextView::resize( VisualComponent& parent )
{
// do resizing stuff
parent.Draw();
}

void BorderDecorator::resize()
{
_component->Resize( *this );
}

To implement such a solution, you either need to be able to modify the
classes in question, or the original designer would have to have
thought of the problem and created the appropriate passthrough
functions. A passthrough function would be needed whenever a concrete
class calls a member-function of the ABC.

Of course, the passthrough function will have to be part of the
VisualComponent interface, probably as a protected pure virtual
member-function.

I forgot to mention... BorderDecorator will of course also need to
implement resize( VisualComponent&). That should be done like this:

void BorderDecorator::resize( VisualComponent& parent )
{
_component->resize( parent );
}

So the top-level decorator has its 'resize()' function called, the
interum decorators have their 'resize(VisualComponent&)' functions
called, the bottom-level object also has it's
'resize(VisualComponent&)' function called, in which it resizes and
calls parent.draw(). 'parent' will be the top-level object.
Thanks for your answer. Nice idea ! Let me see if I understand it
correctly. The TextView will finally recieve the top-level decorator
pointer in its Resize(VisualComponent& parent), so the parent is the
top-level decorator and then the Draw() method will be called correctly
whether it was decorated or not. Really elegant solution. Thanks a lot
!

Gregory

Dec 15 '06 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Tim Smith | last post by:
Dear All, Silly question, but I am having trouble understanding the diagram on the inside back cover entitled "Design Pattern Relationships." It shows the relationships between all of the...
8
by: Alex Vinokur | last post by:
Any links to get started with Design Patterns, including samples? Thanks in advance. Alex Vinokur email: alex DOT vinokur AT gmail DOT com http://mathforum.org/library/view/10978.html...
11
by: FluffyCat | last post by:
In Febraury - April of 2002 I put together in Java examples of all 23 of the classic "Gang Of Four" design patterns for my website. Partly I wanted to get a better understanding of those patterns....
3
by: yb | last post by:
Hi, I just started reading design patterns and looking at the Lexi example. I'm very new to this so please bear with me. I understand the Decorator pattern, but a bit confused by the Maze...
13
by: Don Miller | last post by:
Here's what I want to do... sorry for the lengthy description ;-) I have an inventory tracking system with items that I track stock levels on. Some items are counted with decimal precision...
5
by: Doug | last post by:
I am looking at using the decorator pattern to create a rudimentary stored proc generator but am unsure about something. For each class that identifies a part of the stored proc, what if I want to...
1
by: Doug | last post by:
I am looking at using the decorator pattern to create a rudimentary stored proc generator but am unsure about something. For each class that identifies a part of the stored proc, what if I want to...
11
by: George Sakkis | last post by:
I have a situation where one class can be customized with several orthogonal options. Currently this is implemented with (multiple) inheritance but this leads to combinatorial explosion of...
8
by: Chris Forone | last post by:
hello group, is there a possibility to implement the decorator-pattern without new/delete (nor smartpt)? if not, how to ensure correct deletion of the objects? thanks & hand, chris
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.