Looking for a design pattern

S

Steve

Hi,

I just know there must be some kind of well-known design pattern here, but
I'll be damned if I can find it...

Let me explain my situation.

I have a hierarchy of classes for a GUI. All derived from class 'Primitive'.
Fine so far.

I want to add styled 'themes' to my framework so objects will be drawn to
look the same for a certain theme. In doing this, I free up the
responsibility of the base classes in knowing how to draw themselves (they
still do other stuff like event handling, etc.), so I can reuse the classes
in other applications, but have them drawn differently.

I'm just stuck trying to come up with the best way to do this.

My solution at the moment (but I'm still not happy with it) is:

Primitive::Draw forwards drawing responsibility to
GetCurrentTheme()->DrawObject( this, GetRect() ).

Because the Theme object doesn't know what derived Primitive is being drawn
at this point, it has to dynamic_cast the base class pointer to find out
what type of object is really being drawn, and draw that particular type of
object.

The thinking behind this was that a 'default' theme could cope with drawing
the most basic primitives - buttons, check boxes, etc. in a default style.
If it gets a primitive it doesn't know about, it draws nothing.

As the framework is extended new types of primitive are added, and, in
particular, specific applications may use their own primitives.

So, as the types of primitive are extended, so too are themes to cope with
drawing them.

It just feels awkward having to use dynamic_cast to work out exactly what
type of object will be drawn, and I can't help but think there must be some
other way to do this.


TIA for any advice. I'll be happy explain more if required.
 
P

Phlip

Steve said:
My solution at the moment (but I'm still not happy with it) is:

Primitive::Draw forwards drawing responsibility to
GetCurrentTheme()->DrawObject( this, GetRect() ).

Because the Theme object doesn't know what derived Primitive is being drawn
at this point, it has to dynamic_cast the base class pointer to find out
what type of object is really being drawn, and draw that particular type of
object.

You are asking for "double dispatch". The DrawObject should dispatch based
on both the types of the theme and the primitive. This is the Visitor
Pattern.

However, your concern for getting this design "right" might betray your
concern that you can't change these classes, after they work right, to
retrofit a pattern. And that concern might lead you to "overdesign" the
situation. If your themes are very similar, for example, you could need
"less" of a pattern. But if you commit to such code, and its requirements
change in the future, you might fear that you will then need to hack the
design, or change the design and risk bugs. So the fear will drive you to
overdesign now, rather than debug later.

Read /Refactoring to Patterns/. It will recommend that all features (even
GUI features) come with a complete suite of unit tests. If you have them,
you can refactor in tiny bits, and expect all the tests to pass between each
bit. This technique makes bugs very rare, because if the tests fail you can
use Undo and try again. A failing test indicates you forgot something in
your latest edit, so you can't procede until you remember it.

To write unit tests for GUIs, start with this checklist:

http://www.c2.com/cgi/wiki?TestFirstUserInterfacesPrinciples

Then, generally, Google for:

GUI phlip reveal
 
V

Victor Bazarov

Steve said:
I just know there must be some kind of well-known design pattern
here, but I'll be damned if I can find it...

Adapter, Proxy, Bridge. Depends on how you choose to implement
it in your particular solution.

Also, your objects that don't know how to draw themselves in terms
of the display, but do know how to draw them in terms of some kind
of elements they consist of (border, face, text, etc.), are basically
composites. Your Theme should provide the necessary "callbacks" or
"tools" from a "kit" that would do the drawing of those elements.
Every "Primitive" (which now is a composite of "elements") will then
call Theme's methods to represent themselves in terms of that Theme.
I am not sure under what pattern this falls. Double dispatch?

V
 
B

ben

1) Figure out what can be drawn completely without current theme;
2) Figure out what can be drawn with little information from current theme
(background color, foreground color, etc)
3) Figure out what must be drawn by the theme (rounded cornor, transparency,
etc)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top