关于列表项及其类设计的意见

Posted

技术标签:

【中文标题】关于列表项及其类设计的意见【英文标题】:Opinions about list item and its class design 【发布时间】:2009-09-19 14:52:21 【问题描述】:

我目前正在设计一个列表小部件以添加到我的小部件引擎中。由于每个元素的视觉方面都是在代码之外定义的,因此我可以重用大部分代码库。例如选项卡按钮实际上是复选框。新模板需要时间来实现,因为它们至少应该在设计应用程序中有一个查看器。

我已经有一个复选框的实现。它有 2 个状态(选中/未选中)和 5 个子状态:正常、悬停/活动、鼠标按下、禁用和状态转换。复选框模板具有文本属性、图标(可选)和边框(可以调整大小)。还有状态和子状态转换。图标和边框都是动画的。

我关心的是列表项。它们与复选框非常相似。因此,我打算为列表项使用复选框模板。但是,我需要列表项的四种模式:简单(仅文本)、带图标、带复选框和带单选按钮(单选按钮源自复选框和 IRadioButton 接口)。这里是它的结构:

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

我希望实现这样的东西。 ListItemBase 应该从 IWidgetObject 派生。这是合乎逻辑的还是有更好的选择。

  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 将有 2 个不同的复选框功能,我还想隐藏 ListItemBase 的 check() 函数(重命名它)。那我应该这样实现吗?

  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
  

但是这次我在 ListItemRadio 中有 2 个 IWidgetObjects,我应该克服实现常用功能。但是 ListItemBase 必须将 IWidgetObject 的所有内容都映射到 Checkbox。

是否可以使用虚拟继承来解决这些问题,例如委托给姊妹类(复选框)。还有一个问题,虽然 IWidgetObject 看起来像一个接口,但多年来它拾取了一些常见的实现,但我认为这不会是一个问题。

还有一个问题。 Checkbox 类具有非平凡的构造函数。是否可以这样写:

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

这会解决很多问题。欢迎任何想法。

感谢您阅读所有这些内容

【问题讨论】:

【参考方案1】:

我不知道你的“小部件引擎”和“模板”的细节,所以也许你的设计方式现在迫使你动手(我希望不是!),但在我看来,你'在自然设计将使用包含和组合的地方重新使用继承——这是一个更可取的解决方案。即,您说的是列表项“IS-A”复选框,而自然状态是列表项“HAS-A”复选框(单选按钮也是如此)。

如果小部件引擎的设计迫使您以这种方式操作,那么最终需要多重继承也就不足为奇了——但这可能会增加其自身的复杂性,而且无论如何,子类化导致强耦合和低灵活性,而包含和组合在这些方面更好。我推荐阅读经典的Design Patterns,它很好地解释了这些问题。

不管怎样,如果你困在这种设计中,那么,是的,就像你说的,可能的:

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

但这并不意味着 Checkbox 基类构造函数在 IWidgetObject 的构造函数之前执行:这取决于您声明基类的顺序(如果将 IWidgetObject 声明为第一个基类,则其构造函数将在另一个之前执行) .

【讨论】:

实际上在 is-a 关系中没有强制力(除了它是一个可以包含的 IWidgetObject),但我更喜欢这种方式。正如您所说,不管这种偏好如何,保留这种设计太复杂了。【参考方案2】:

好的,我想出一个主意

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

你怎么看?

【讨论】:

以上是关于关于列表项及其类设计的意见的主要内容,如果未能解决你的问题,请参考以下文章

关于设计模式的六大原则

Java实验项目三——编程实现Person类,学生类的设计及其继承关系

高级控件

从设计基类及其派生类看继承关系

Chp10 10.7

如何获取主类的 Java 类依赖项列表?