工厂模式
核心:
解耦创建逻辑 · 多种子类 · 条件分支创建
思想及适用场景:
主要用于封装对象的创建逻辑,调用方只关心"我要什么",不关心"怎么造"。
当需要根据条件创建不同子类时尤其有用。
示例
// 产品协议
protocol Button {
func render()
func tap()
}
// 具体产品
struct IOSButton: Button {
func render() { print("渲染 iOS 风格圆角按钮") }
func tap() { print("iOS 触感反馈") }
}
struct AndroidButton: Button {
func render() { print("渲染 Material Design 按钮") }
func tap() { print("Android Ripple 动效") }
}
// 工厂 —— 根据不同平台,决定创建哪种 Button
enum Platform { case iOS, android }
struct ButtonFactory {
// 提供公共创建方法,传入不同条件/场景,返回协议对象 (调用方不需要知道具体类型)
static func makeButton(for platform: Platform) -> Button {
switch platform {
case .iOS: return IOSButton()
case .android: return AndroidButton()
}
}
}
// 使用:调用方不需要知道具体类型
let btn = ButtonFactory.makeButton(for: .iOS)
btn.render() // 渲染 iOS 风格圆角按钮
btn.tap() // iOS 触感反馈
进阶:抽象工厂模式
思路:
在工厂模式基础上再抽象一层。普通工厂只生产一种产品,抽象工厂负责生产一族相关产品,保证同一工厂出来的产品风格一致,且调用方完全不依赖具体类。
核心区别一句话:工厂方法解决"造哪个",抽象工厂解决"造哪套"。
示例
- 抽象产品协议
protocol Button {
func render()
func onTap()
}
protocol TextField {
func render()
func onInput(_ text: String)
}
// MARK: - iOS 具体产品
struct IOSButton: Button {
func render() { print(" 🔵 渲染 iOS 圆角按钮") }
func onTap() { print(" 📳 iOS Haptic 触感反馈") }
}
struct IOSTextField: TextField {
func render() { print(" 🔵 渲染 iOS 下划线输入框") }
func onInput(_ text: String) { print(" iOS 输入: \(text)") }
}
// MARK: - Android 具体产品
struct AndroidButton: Button {
func render() { print(" 🟢 渲染 Material Design 按钮") }
func onTap() { print(" 💧 Android Ripple 水波动效") }
}
struct AndroidTextField: TextField {
func render() { print(" 🟢 渲染 Material 边框输入框") }
func onInput(_ text: String) { print(" Android 输入: \(text)") }
}
- 抽象工厂协议
protocol UIFactory {
func makeButton() -> Button
func makeTextField() -> TextField
}
// MARK: - 具体工厂(每个工厂只生产同一风格的产品族)
struct IOSFactory: UIFactory {
func makeButton() -> Button { IOSButton() }
func makeTextField() -> TextField { IOSTextField() }
}
struct AndroidFactory: UIFactory {
func makeButton() -> Button { AndroidButton() }
func makeTextField() -> TextField { AndroidTextField() }
}
- 调用,客户端(只依赖抽象,不知道任何具体类型)
class LoginVC {
private let button: Button
private let textField: TextField
// 注入工厂,由外部决定平台风格
init(factory: UIFactory) {
self.button = factory.makeButton()
self.textField = factory.makeTextField()
}
func show() {
print("--- 渲染登录界面 ---")
textField.render()
textField.onInput("alice@example.com")
button.render()
button.onTap()
}
}
// MARK: - 运行
print("=== iOS 平台 ===")
LoginVC(factory: IOSFactory()).show()
print("\n=== Android 平台 ===")
LoginVC(factory: AndroidFactory()).show()
- 扩展
只需 新增 品类 和 工厂。不改 旧代码,不改调用方式(开闭原则),只需传递 新变量
// 新增 macOS 产品
struct MacOSButton: Button {
func render() { print(" 🖥 渲染 macOS NSButton") }
func onTap() { print(" 🖱 macOS 点击事件") }
}
struct MacOSTextField: TextField {
func render() { print(" 🖥 渲染 macOS NSTextField") }
func onInput(_ text: String) { print(" macOS 输入: \(text)") }
}
// 新增工厂
struct MacOSFactory: UIFactory {
func makeButton() -> Button { MacOSButton() }
func makeTextField() -> TextField { MacOSTextField() }
}
// 使用 —— LoginScreen 代码零修改
LoginScreen(factory: MacOSFactory()).show()
适用场景总结:
当系统需要独立于产品创建方式、且需要保证同一产品族的一致性时——比如跨平台 UI 套件、换肤主题、多数据库驱动(SQLite / CoreData / CloudKit)——抽象工厂是最合适的选择。