工厂方法可能是我们最常见的模式之一。
意图
定义一个用来创建子对象的接口,让子类决定实例化哪一个类。
动机
举个例子,我们做一个 App,这个 App 中有各种样式的弹开框。我们可能会定义许多对应样式的弹开的子类,可以用户层其实并不关心你哪个样式的弹框需要对应哪一个子类。用户层只关心创建一个弹框,显示弹框。
而工厂方法模式正好给我们提供了这类型问题的解决方案。
适应性
- 当一个类不知道它所必须创建的对象的类的时候。
- 一个类希望由他的子类来指定他所创建的对象的时候。
- 当类将创建对象的职责委托给多个子类中的某一个,并且你希望将子类是代理者这一信息的局部化。
结构
工厂方法结构.png参与者
- Product
—— 定义工厂方法所创建的对象的接口
- ConcreteProduct
—— 实现Product接口
- Creator
—— 声明工厂方法,该方法返回一个 Product 类型的对象。Creator 也可以定义一个工厂方法的缺省实现,它返回一个缺省的 ConcreteProduct 对象。
—— 可以调用工厂方法以创建一个 Product 对象。
- ConcreteCreator
—— 重定义工厂方法以返回一个 ConcreteProduct 实例。
协作
- Creator 依赖于它的子类来定义工厂方法,所以它返回一个适当的 ConcreteProduct 实例。
效果
缺点
工厂方法的一个潜在缺点在于客户可能仅仅为了创建一个特定的 ConcreteProduct 对象,就不得不创建 Creator 的子类。
优点
- 为子类提供hook
- 连接平行的类层数
实现
主要有两种不同情况
- Creator 类是一个抽象类并且不提供它所声明的工厂方法的实现。
- Creator 是一个具体的类而且为工厂方法提供一个缺省的实现。
参数化工厂方法
使得工厂方法可以创建多种产品。工厂方法采样一个标识要创建的对象种类的参数。
使用模板
我们可以通过模板(泛型)来避免为了创建一个特定的 ConcreteProduct 对象,而不创建 Creator 的子类的问题。
代码示例
最后还是更具惯例来段代码示例,示例中使用的是参数化的工厂方法。我这边还是以创建弹框为例子。
弹框样式
我们先明确一下需求,我们需要通过一个工厂方法来创建 3 种样式的弹框。
分别是:
- done 只有一个确定按钮的弹框
- comfirm 有两个按钮(确定和取消)
- share 常见的分享用的弹框
enum AlertViewType {
case done, comfirm, share
}
创建 Product 和 Creator
这里我们定义了一个 AlertView
它及时 Product
也是 Creator
。
它定义了弹框对应的接口 show
,也定义了工厂方法 createAlertView
。
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
接口。
class DoneAlertView: AlertView {
override func show() {
print("完成确认的弹框样式。")
}
}
class ComfirmAlertView: AlertView {
override func show() {
print("有两个按钮(确定和取消)的弹框样式。")
}
}
class ShareAlertView: AlertView {
override func show() {
print("常见的分享用的弹框的弹框样式。")
}
}
用户使用
我们通过工厂方法来创建对象,具体创建什么对象有参数决定。创建出来的对象调用 show
接口,执行它所对应的对象的操作。
let doneAlert = AlertView.createAlertView(with: .done)
doneAlert.show()
let comfirmAlert = AlertView.createAlertView(with: .comfirm)
comfirmAlert.show()
let shareAlert = AlertView.createAlertView(with: .share)
shareAlert.show()
打印信息
完成确认的弹框样式。
有两个按钮(确定和取消)的弹框样式。
常见的分享用的弹框的弹框样式。
总结
工厂方法可以让用户使用接口时不需要关心他真实对应的哪一个类,不需要关心平行子类的区别。
欢迎讨论、批评、指错。
网友评论