views:

54

answers:

2

I'm currently designing a list widget to add to my widget engine. Since every elements visual aspects are defined outside the code I can reuse most of the code base. For instance tab buttons are actually checkboxes. New templates take time to implement since they should have at least a viewer in design application.

I already have an implementation for a checkbox. It has 2 states (checked/unchecked) and 5 substates: normal, hover/active, mousedown, disabled and in state transition. A checkbox template has text properties, icon (optional), and border (might be resizable). There are also state and substate transitions. Both icons and borders are animatable.

My concern is about list items. They are quite similar to checkboxes. Therefore, Im planning to use checkbox template for listitems. However, I require four modes of a list item: simple (text only), with icon, with a checkbox and with a radio button (a radio button is derived from a checkbox and IRadioButton interface). Here its structure:

IWidgetObject
      |
   Checkbox       IRadioButton
      \                /
       `--------------´
              |
         RadioButton

I wish to implement something like this. ListItemBase should be derived from IWidgetObject. Is it logical or are there better alternatives.

  class ListItemBase : public Checkbox {
      void Select() { do something; Checkbox::check(); }
  } 

  //This listitem type will have a checkbox without any text
  class ListItemCheckbox : public ListItemBase, private Checkbox {
      check() { update parents checked list; Checkbox::check(); }
  }

  class ListItemRadio : public ListItemBase, private RadioButton, public IRadioButton {
      //here is the problem
  }

ListItemRadio will have 2 distinct checkbox functionality, also I want to hide ListItemBase's check() function (to rename it). Then should I implement it this way?

  class ListItemBase : private Checkbox, public IWidgetObject {
      void Select() { do something; Checkbox::check(); }

      //does this even works? (layer is a variable)
      using Checkbox::layer;
  } 

  //This listitem type will have a checkbox without any text
  class ListItemCheckbox : public ListItemBase, private Checkbox {
      check() { update parents checked list; Checkbox::check(); }
  }

  class ListItemRadio : public ListItemBase, private RadioButton, public IRadioButton {
      //here is the problem
  }

But this time I have 2 IWidgetObjects in ListItemRadio, which I should overcome implementing common functions. But ListItemBase will have to map everything of IWidgetObject to Checkbox.

Is it possible to use virtual inheritance to solve these problems, like delegating to sister class (checkbox). There is also one more problem, although IWidgetObject seems like an interface, over the years it picked up some common implementation, but I dont think it will be a problem.

Also there is one more problem. Checkbox class has non-trivial constructor. Is it possible to write something like this:

 ListItemBase(IWidgetContainer &container, CheckboxBP &blueprint) : 
        Checkbox(container, blueprint), IWidgetObject(this) {
 }

This would solve lots of problems. Any idea is welcome.

Thank you for even reading all these

A: 

OK, I come up with an idea

                  IWidgetObject
                        |
 ICheckbox        CheckboxBase     IRadioButton
  |  \               /  |  \           /    |
  |   `-------------´   |   `---------´     |
  |          |          |        |          |
  |    Checkbox         |    RadioButton    |
  |                     |                   |
  |               ListItemBase              |
   \                |      |               /
    `---------------´      `--------------´
           |                      |
     ListItemCheckbox        ListItemRadioButton

What do you think?

Cem Kalyoncu
+2  A: 

I do not know the details of your "widget engine" and "templates", so maybe you've designed that in a way that now forces your hand (I hope not!), but it seems to me that you're using inheritance where the natural design would, instead, use containment and composition -- a much preferable solution. I.e., you're saying that a list item "IS-A" checkbox, while the natural state of affair is that a list item "HAS-A" checkbox (and similarly for radio buttons).

If you're forced to operate this way by the design of the widget engine, then it's not surprising that you end up with the need for multiple inheritance -- but that can add its own complications, and, in any case, subclassing leads to strong coupling and low flexibility, while containment and composition are better in these regards. I recommend reading the classic Design Patterns, which explains these issues very well.

Anyway, if you are trapped into this kind of design, then, yes, it is possible, as you say, to write:

ListItemBase(IWidgetContainer &container, CheckboxBP &blueprint) : 
        Checkbox(container, blueprint), IWidgetObject(this) {
 }

However this does not imply that the Checkbox base class constructor executes before the IWidgetObject's one: that depends on the order in which you have declared your bases (if you declare IWidgetObject as the first base, its constructor will execute before the other).

Alex Martelli
Actually there no force in is-a relationship (except it to be an IWidgetObject which can be contained), but I prefer it that way. Regardless of that preference, as you say, it is too complex to keep that design.
Cem Kalyoncu