iOS开发设计模式-工厂模式

16 阅读3分钟

工厂模式

核心:

解耦创建逻辑 · 多种子类 · 条件分支创建

思想及适用场景:

主要用于封装对象的创建逻辑,调用方只关心"我要什么",不关心"怎么造"。

当需要根据条件创建不同子类时尤其有用。

示例

// 产品协议
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)——抽象工厂是最合适的选择。