iOS设计模式之策略模式

163 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情

本文主要介绍iOS设计模式中的策略模式,通过定义一些算法,把他们封装起来,形成每个算法对应一个对象,形成策略。

1. 什么是策略模式

有的时候我们处理一些复杂的场景,会把一堆算法塞到同一段代码中,然后使用if-elseswitch-case条件语句来决定使用哪个算法?这些算法可能是一推相似的类函数或方法,用以解决相关问题。
比如,我有一个验证输入数据的判断,数据本身可以是任何数据类型(如CGFloat,Double,NSString等)每种数据需要不同的验证算法。如果能把每个算法封装成一个对象,那么就能消除数据类型类型决定使用什么算法的一堆if-elseswitch-case条件语句。
假如你需要前往机场。 你可以选择乘坐公共汽车、 预约出租车或骑自行车。 这些就是你的出行策略。 你可以根据预算或时间等因素来选择其中一种策略。 面向对象设计过程中,我们可以把相关算法分离为不同的类,成为策略。与这种做法有关的一种设计模式称为策略模式。策略模式中有一个关键角色是策略类,它为所有支持获得或相关的算法声明了一个共同接口。另外,还有使用策略接口来实现相关算法的具体策略。

策略模式:定义一系列算法,把他们一个个封装起来,并且它们可以相互替换,本模式是的算法可独立于使用它的客户而变化。

2. 什么时候使用策略模式

  • 一个类在其操作中使用多个条件语句来定义许多行为。我们可以把相关的条件分支移到他们自己的策略类中。
  • 需要算法的各种变体
  • 需要避免把复杂的,与算法相关的数据结构暴漏给客户端。

3.代码展示

import XCTest

/// The Context defines the interface of interest to clients.
class Context {

    /// The Context maintains a reference to one of the Strategy objects. The
    /// Context does not know the concrete class of a strategy. It should work
    /// with all strategies via the Strategy interface.
    private var strategy: Strategy

    /// Usually, the Context accepts a strategy through the constructor, but
    /// also provides a setter to change it at runtime.
    init(strategy: Strategy) {
        self.strategy = strategy
    }

    /// Usually, the Context allows replacing a Strategy object at runtime.
    func update(strategy: Strategy) {
        self.strategy = strategy
    }

    /// The Context delegates some work to the Strategy object instead of
    /// implementing multiple versions of the algorithm on its own.
    func doSomeBusinessLogic() {
        print("Context: Sorting data using the strategy (not sure how it'll do it)\n")

        let result = strategy.doAlgorithm(["a", "b", "c", "d", "e"])
        print(result.joined(separator: ","))
    }
}

/// The Strategy interface declares operations common to all supported versions
/// of some algorithm.
///
/// The Context uses this interface to call the algorithm defined by Concrete
/// Strategies.
protocol Strategy {

    func doAlgorithm<T: Comparable>(_ data: [T]) -> [T]
}

/// Concrete Strategies implement the algorithm while following the base
/// Strategy interface. The interface makes them interchangeable in the Context.
class ConcreteStrategyA: Strategy {

    func doAlgorithm<T: Comparable>(_ data: [T]) -> [T] {
        return data.sorted()
    }
}

class ConcreteStrategyB: Strategy {

    func doAlgorithm<T: Comparable>(_ data: [T]) -> [T] {
        return data.sorted(by: >)
    }
}

/// Let's see how it all works together.
class StrategyConceptual: XCTestCase {

    func test() {

        /// The client code picks a concrete strategy and passes it to the
        /// context. The client should be aware of the differences between
        /// strategies in order to make the right choice.

        let context = Context(strategy: ConcreteStrategyA())
        print("Client: Strategy is set to normal sorting.\n")
        context.doSomeBusinessLogic()

        print("\nClient: Strategy is set to reverse sorting.\n")
        context.update(strategy: ConcreteStrategyB())
        context.doSomeBusinessLogic()
    }
}

执行结果

Client: Strategy is set to normal sorting.

Context: Sorting data using the strategy (not sure how it'll do it)

a,b,c,d,e

Client: Strategy is set to reverse sorting.

Context: Sorting data using the strategy (not sure how it'll do it)

e,d,c,b,a

4. 总结

策略模式在iOS代码中很常见。 它经常在各种框架中使用, 能在不扩展类的情况下向用户提供改变其行为的方式。策略模式可以通过允许嵌套对象完成实际工作的方法以及允许将该对象替换为不同对象的设置器来识别。