1

假设我想从头开始制作一个自定义按钮:

  • BasicButton : NSObject
    所以我创建了一个类,它知道如何在单击按钮时处理鼠标事件并将消息转发给感兴趣的接收者(通过委托、目标/动作、通知等)。
  • SolidColorButton : BasicButton : NSObject
    我的按钮现在可以工作了,但它是不可见的,所以我决定画一个纯色背景来使按钮栩栩如生(在 UI 设计方面不是很好,但让我们假装吧)。
  • LabelledButton : SolidColorButton : BasicButton : NSObject
    现在假设我想在按钮上添加标签,所以我创建了另一个可以在按钮上绘制文本的子类。

所以现在我有一个可以处理鼠标事件、绘制纯色背景和绘制一些文本的按钮。但是,如果我决定需要一个带有背景图像而不是纯色的按钮,但它仍然知道如何绘制标签,现在会发生什么?这就是单继承子类方法失败的地方。我不能随意将鼠标处理、标签绘制和图像绘制结合起来,我只能选择继承链下游的细化级别。

所以我想我的问题是:实现这些单独的模块的方法是什么,以便它们可以混合和匹配以创建某种后代对象,它具有所需模块的组合功能,没有别的?

例如,我希望能够编写如下模块:

  • 鼠标处理
  • 键盘处理
  • 纯色背景
  • 图像背景
  • 标签
  • 等等

然后有能力制作一个特定的按钮:a)处理鼠标,b)绘制背景,c)有一个标签;没有别的了。

这个问题具体到如何在 Objective-C 或另一种单继承 OOP 语言中做到这一点。在 Ruby 中,一种方法是使用 mixins。

4

2 回答 2

3

你已经注意到继承在这里是个坏主意。装饰器模式会派上用场:您将拥有一个按钮类和多个“装饰”按钮(包装并添加功能)并且可以任意组合的装饰器。

类图:

 +---------------+     innerButton
 |ButtonInterface+------------------------+
 +---------------+ 1                      |
        ^    ^                            |
        |    |                            |
        |    +-------------+              |
 +------+------+   +-------+-------+      |
 | BasicButton |   |ButtonDecorator+------+
 +-------------+   +---------------+
                     ^           ^
                     |           |  ...
                     |           |
+--------------------+----+ +----+------------------+
|SolidColorButtonDecorator| |LabelledButtonDecorator|  ...
+-------------------------+ +-----------------------+

对象图(对于您的示例):

+----------------------------+
|MouseHandlingButtonDecorator|
+-----+----------------------+
      |
     1| innerButton
+-----+-------------------+
|BackgroundButtonDecorator|
+-----+-------------------+
      |
     1| innerButton
+-----+-----------------+
|LabelledButtonDecorator|
+-----+-----------------+
      |
     1| innerButton
+-----+-----+
|BasicButton|
+-----------+
于 2013-02-14T12:50:23.473 回答
1

另一种选择是组合设计模式,但是,它被修改为看起来像“装饰器模式”。

以下示例仅适用于绘图行为,不适用于鼠标或键盘行为。忽略下图中的点。

注意:它更像 C++ 或 C#,请忽略与 Objective-c 的细微差别。

首先,您需要一个按钮类,将“绘制”功能“委托”给成员或项目。让我们首先展示主类本身。

................................................................................
..+--------------------------------+..../|..+--------------------------------+..
..|        GraphicObjectClass      |.../.|..|      CompositeButtonClass      |..
..+--------------------------------*--<..|--*--------------------------------+..
..| [+]  void Draw(); <<virtual>>  |...\.|..| [+]  void Draw(); <<override>> |..
..+--------------------------------+....\|..+--------------------------------+..
................................................................................

假设您想要一个按钮,并且:

  • 绘制边框的“模块类”
  • 绘制背景、纯色或图案的“模块类”
  • 绘制文本标签、粗体、斜体、字体名称的“模块类”

第二个图表显示了单独执行此操作的单独“模块”或类:

................................................................................
..+--------------------------------+............................................
..|        GraphicObjectClass      |............................................
..+--------------------------------+............................................
..| [+]  void Draw(); <<virtual>>  |............................................
..+---------------*----------------+............................................
..................|.............................................................
..................^.............................................................
................./.\............................................................
................/...\...........................................................
.............../--+--\..........................................................
..................|.............................................................
..+---------------*----------------+.../|...+--------------------------------+..
..|      ButtonComponentClass      |../.|...|      SolidColorButtonClass     |..
..+--------------------------------+-<..|-*.+--------------------------------+..
..| [+]  void Draw(); <<virtual>>  |..\.|.|.| [+]  void Draw(); <<override>> |..
..+--------------------------------+...\|.|.+--------------------------------+..    
..........................................|.....................................
..........................................|.+--------------------------------+..
..........................................|.|       LabeledButtonClass       |..
..........................................|.+--------------------------------+..
..........................................*-* [+]  void Draw(); <<override>> |..
..........................................|.+--------------------------------+..
..........................................|.....................................
..........................................|.+--------------------------------+..
..........................................|.|        BorderButtonClass       |..
..........................................|.+--------------------------------+..
..........................................*-* [+]  void Draw(); <<override>> |..
............................................+--------------------------------+..
................................................................................

让我们将组件集成到按钮中,注意我为继承关联制作了一个与其他关联不同的图表。

.......................................................................................
.+--------------------------------------------+.....+--------------------------------+.
.|              CompositeButtonClass          |.....|      SolidColorButtonClass     |.
.+--------------------------------------------+.....+--------------------------------+.
.| [+] ButtonComponentClass* Background       *-----* [+]  void Draw(); <<override>> |.
.|                                            |.....+--------------------------------+.
.| [+] ButtonComponentClass* Border           *---*....................................
.|                                            |...|.+--------------------------------+.
.| [+] ButtonComponentClass* Label            *-*.|.|       LabeledButtonClass       |.
.+--------------------------------------------+.|.|.+--------------------------------+.
.| [+] void Draw();               <<virtual>> |.|.+-* [+]  void Draw(); <<override>> |.
.+--------------------------------------------+.|...+--------------------------------+.
................................................|......................................
................................................|...+--------------------------------+.
................................................|...|        BorderButtonClass       |.
................................................|...+--------------------------------+.
................................................*---* [+]  void Draw(); <<override>> |.
....................................................+--------------------------------+.
.......................................................................................

现在,您将拥有一个按钮类,它会将“绘制”功能“委托”给成员或项目。让我们首先展示主类本身。

virtual /* override */ void CompositeButtonClass::Draw()
{
   // [Background Draw]     
   this->Background->Draw();

   // [Border Draw]
   this->Border->Draw();

   // [Label Draw]
   this->Label->Draw();
}

只是一个建议。

干杯。

于 2013-02-14T18:14:07.613 回答