设计模式笔记及Swift上的实现之三『FACTORY METHOD(工厂方法)』

b6867c795a71

工厂方法可能是我们最常见的模式之一。

意图

定义一个用来创建子对象的接口,让子类决定实例化哪一个类。

动机

举个例子,我们做一个 App,这个 App 中有各种样式的弹开框。我们可能会定义许多对应样式的弹开的子类,可以用户层其实并不关心你哪个样式的弹框需要对应哪一个子类。用户层只关心创建一个弹框,显示弹框。

而工厂方法模式正好给我们提供了这类型问题的解决方案。

适应性

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 一个类希望由他的子类来指定他所创建的对象的时候。
  • 当类将创建对象的职责委托给多个子类中的某一个,并且你希望将子类是代理者这一信息的局部化。

结构

工厂方法结构

参与者

  • Product

    —— 定义工厂方法所创建的对象的接口

  • ConcreteProduct

    —— 实现Product接口

  • Creator

    —— 声明工厂方法,该方法返回一个 Product 类型的对象。Creator 也可以定义一个工厂方法的缺省实现,它返回一个缺省的 ConcreteProduct 对象。
    —— 可以调用工厂方法以创建一个 Product 对象。

  • ConcreteCreator

    —— 重定义工厂方法以返回一个 ConcreteProduct 实例。

协作

  • Creator 依赖于它的子类来定义工厂方法,所以它返回一个适当的 ConcreteProduct 实例。

效果

缺点

工厂方法的一个潜在缺点在于客户可能仅仅为了创建一个特定的 ConcreteProduct 对象,就不得不创建 Creator 的子类。

优点

  • 为子类提供hook
  • 连接平行的类层数

实现

主要有两种不同情况

  • Creator 类是一个抽象类并且不提供它所声明的工厂方法的实现。
  • Creator 是一个具体的类而且为工厂方法提供一个缺省的实现。

参数化工厂方法

使得工厂方法可以创建多种产品。工厂方法采样一个标识要创建的对象种类的参数。

使用模板

我们可以通过模板(泛型)来避免为了创建一个特定的 ConcreteProduct 对象,而不创建 Creator 的子类的问题。

代码示例

最后还是更具惯例来段代码示例,示例中使用的是参数化的工厂方法。我这边还是以创建弹框为例子。

弹框样式

我们先明确一下需求,我们需要通过一个工厂方法来创建 3 种样式的弹框。
分别是:

  • done 只有一个确定按钮的弹框
  • comfirm 有两个按钮(确定和取消)
  • share 常见的分享用的弹框
1
2
3
enum AlertViewType {
case done, comfirm, share
}

创建 Product 和 Creator

这里我们定义了一个 AlertView 它及时 Product 也是 Creator
它定义了弹框对应的接口 show,也定义了工厂方法 createAlertView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class AlertView {
static func createAlertView(with type: AlertViewType) -> AlertView {
switch type {
case .done:
return DoneAlertView()
case .comfirm:
return ComfirmAlertView()
case .share:
return ShareAlertView()
}
}
func show() {
}
}

定义 ConcreteProduct

这里我定义了 3 种类型的产品

  • DoneAlertView 只有一个确定按钮的弹框
  • ComfirmAlertView 有两个按钮(确定和取消)
  • ShareAlertView 常见的分享用的弹框

并各自实现了它们的 show 接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class DoneAlertView: AlertView {
override func show() {
print("完成确认的弹框样式。")
}
}
class ComfirmAlertView: AlertView {
override func show() {
print("有两个按钮(确定和取消)的弹框样式。")
}
}
class ShareAlertView: AlertView {
override func show() {
print("常见的分享用的弹框的弹框样式。")
}
}

用户使用

我们通过工厂方法来创建对象,具体创建什么对象有参数决定。创建出来的对象调用 show 接口,执行它所对应的对象的操作。

1
2
3
4
5
6
7
8
let doneAlert = AlertView.createAlertView(with: .done)
doneAlert.show()
let comfirmAlert = AlertView.createAlertView(with: .comfirm)
comfirmAlert.show()
let shareAlert = AlertView.createAlertView(with: .share)
shareAlert.show()

打印信息

1
2
3
完成确认的弹框样式。
有两个按钮(确定和取消)的弹框样式。
常见的分享用的弹框的弹框样式。

总结

工厂方法可以让用户使用接口时不需要关心他真实对应的哪一个类,不需要关心平行子类的区别。

附:Playground 代码

欢迎讨论、批评、指错。