哪种设计模式适合从模块化子件创建对象?

时间:2013-02-14 12:37:40

标签: objective-c oop design-patterns

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

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

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

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

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

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

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

这个问题特定于如何在Objective-C或其他单继承OOP语言中执行此操作。在Ruby中,一种方法是使用mixins。

2 个答案:

答案 0 :(得分:3)

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

类图:

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

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

+----------------------------+
|MouseHandlingButtonDecorator|
+-----+----------------------+
      |
     1| innerButton
+-----+-------------------+
|BackgroundButtonDecorator|
+-----+-------------------+
      |
     1| innerButton
+-----+-----------------+
|LabelledButtonDecorator|
+-----+-----------------+
      |
     1| innerButton
+-----+-----+
|BasicButton|
+-----------+

答案 1 :(得分: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();
}

只是一个建议。

干杯。