iOS设计模式-策略模式

思想

把"算法/行为"从"使用它的类"中抽离出来,让客户端在运行时动态切换策略,而不需要修改 Context 的代码。(遵循开闭原则------对扩展开放,对修改封闭)

三个角色

协议:行为抽象

策略者:定义和实现各自的行为策略

上下文统筹者:针对各场景,委托对应的策略者,进行行为处理。

常用场景

庞大的 if-else / switch 语句,每个case都有自己的处理逻辑。

  • 支付场景(微信、支付宝、苹果、银行卡等)
  • 表单输入验证(手机号、邮箱、身份证、密码格式等)
  • 社交分享平台
  • 排序算法(按价格、销量、距离等)

模板

swift 复制代码
// 1. 抽象策略(协议)
protocol Strategy {
    func execute(data: [Int]) -> [Int]   // 示例:对数据 进行某种处理
}

// 2. 具体策略 A、B、C...
class ConcreteStrategyA: Strategy { ... }
class ConcreteStrategyB: Strategy { ... }

// 3. 上下文(Context)持有策略引用
class Context {
    private var strategy: Strategy
    
    init(strategy: Strategy) {
        self.strategy = strategy
    }
    
    func setStrategy(_ strategy: Strategy) {
        self.strategy = strategy
    }
    
    func doSomething(with data: [Int]) -> [Int] {
        return strategy.execute(data: data)   // 委托给当前策略 执行
    }
}

支付场景 示例

普通代码

面向过程编程

scss 复制代码
class OrderPayManager{
    func pay(way: Int){
        if way == .alipay {
            alipay()
        }else if way == .wxPay {
            wxpay()
        }else if {
            ...
        }
    }

    func alipay(){
        AliSDK()
        ...
    }
    
    func wxpay(){
        wxSDK()
        ...
    }
}

策略模式封装

  1. 抽象策略协议
less 复制代码
protocol PaymentStrategy {
    func pay(amount: Double, completion: @escaping (Bool, String) -> Void)
}
  1. 具体策略实现
less 复制代码
class AlipayStrategy: PaymentStrategy {
    func pay(amount: Double, completion: @escaping (Bool, String) -> Void) {
        print("🔸 支付宝支付 \(amount) 元")
        // 真实项目中这里调用支付宝 SDK
        completion(true, "支付宝支付成功")
    }
}

class WechatPayStrategy: PaymentStrategy {
    func pay(amount: Double, completion: @escaping (Bool, String) -> Void) {
        print("🔸 微信支付 \(amount) 元")
        // 调用微信支付 SDK
        completion(true, "微信支付成功")
    }
}

class ApplePayStrategy: PaymentStrategy {
    func pay(amount: Double, completion: @escaping (Bool, String) -> Void) {
        print("🔸 Apple Pay \(amount) 元")
        // 调用 PKPaymentAuthorizationViewController
        completion(true, "Apple Pay 支付成功")
    }
}
  1. 上下文(订单支付类)
swift 复制代码
class Order {
    private var paymentStrategy: PaymentStrategy
    
    init(paymentStrategy: PaymentStrategy) {
        self.paymentStrategy = paymentStrategy
    }
    
    // 切换支付方式
    func changePaymentMethod(to strategy: PaymentStrategy) {
        self.paymentStrategy = strategy
    }
    
    // 支付
    func checkout(amount: Double) {
        print("📦 订单金额:\(amount) 元")
        paymentStrategy.pay(amount: amount) { success, message in
            if success {
                print("🎉 \(message)")
            } else {
                print("❌ 支付失败:\(message)")
            }
        }
    }
}
  1. 外界调用
scss 复制代码
let order = Order(paymentStrategy: AlipayStrategy())

order.checkout(amount: 99.9)
// 输出:支付宝支付...

// 用户中途切换支付方式
order.changePaymentMethod(to: ApplePayStrategy())
order.checkout(amount: 199.0)
// 输出:Apple Pay...

输入验证示例

swift 复制代码
protocol ValidationStrategy {
    func isValid(_ input: String) -> Bool
    var errorMessage: String { get }
}

class EmailValidation: ValidationStrategy {
    var errorMessage = "请输入正确的邮箱地址"
    func isValid(_ input: String) -> Bool {
        let regex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: input)
    }
}

class PasswordValidation: ValidationStrategy {
    var errorMessage = "密码至少8位,包含字母和数字"
    func isValid(_ input: String) -> Bool {
        return input.count >= 8 && input.range(of: "[A-Za-z]", options: .regularExpression) != nil
    }
}

// 表单验证器(Context)
class FormValidator {
    private var strategy: ValidationStrategy
    
    init(strategy: ValidationStrategy) {
        self.strategy = strategy
    }
    
    func validate(_ text: String) -> String? {
        return strategy.isValid(text) ? nil : strategy.errorMessage
    }
}

总结

在 Swift 开发中,策略模式几乎是"协议 + 运行时切换" 的最佳实践之一。它让你的代码更加灵活、可测试、可扩展,尤其适合那些"行为/算法经常变化"的场景(支付、验证、排序、AI、日志等)。 如果你在实际项目中遇到"一个类里面有大量 if-else 判断不同行为"的情况,强烈建议立刻重构为策略模式,代码会瞬间清晰很多!

相关推荐
卸任7 小时前
Vibe coding工具使用心得
前端·ai编程
brien98 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance8 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M8 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写8 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李8 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易8 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马8 小时前
前沿视界
前端
kyriewen9 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易9 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员