iOS设计模式之状态模式

语言: CN / TW / HK

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

本文主要介绍iOS设计模中的状态模式,状态模式顾名思义就是通过改变对象的状态从而改变对象的行为。

1. 什么是状态模式

我们通过定义对象的状态从而改变对象的行为,并且你还可将该方法应用在对象上。 假如你有一个 文档Document类。 文档可能会处于 草稿Draft 、  审阅中Moderation和 已发布Published三种状态中的一种。 文档的 publish发布方法在不同状态下的行为略有不同:

  • 处于 草稿状态时, 它会将文档转移到审阅中状态。
  • 处于 审阅中状态时, 如果当前用户是管理员, 它会公开发布文档。
  • 处于 已发布状态时, 它不会进行任何操作。

状态机通常由众多条件运算符 ( if或 switch ) 实现, 可根据对象的当前状态选择相应的行为。  “状态” 通常只是对象中的一组成员变量值。 即使你之前从未听说过有限状态机, 你也很可能已经实现过状态模式。

智能手机的按键和开关会根据设备当前状态完成不同行为

  • 当手机处于解锁状态时, 按下按键将执行各种功能。
  • 当手机处于锁定状态时, 按下任何按键都将解锁屏幕。
  • 当手机电量不足时, 按下任何按键都将显示充电页面。 状态模式建议为对象的所有可能状态新建一个类, 然后将所有状态的对应行为抽取到这些类中。

原始对象被称为上下文(context), 它并不会自行实现所有行为, 而是会保存一个指向表示当前状态的状态对象的引用, 且将所有与状态相关的工作委派给该对象。

状态是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为。

2. 什么时候使用状态模式

以下这些情况可以考虑使用状态模式 - [ ] 如果对象需要根据自身当前状态进行不同行为, 同时状态的数量非常多且与状态相关的代码会频繁变更的话, 可使用状态模式。 - [ ] 如果某个类需要根据成员变量的当前值改变自身行为, 从而需要使用大量的条件语句时, 可使用该模式。 - [ ]  当相似状态和基于条件的状态机转换中存在许多重复代码时, 可使用状态模式。

3. 代码展示

```Swift import XCTest

/// The Context defines the interface of interest to clients. It also maintains /// a reference to an instance of a State subclass, which represents the current /// state of the Context. class Context {

/// A reference to the current state of the Context.
private var state: State

init(_ state: State) {
    self.state = state
    transitionTo(state: state)
}

/// The Context allows changing the State object at runtime.
func transitionTo(state: State) {
    print("Context: Transition to " + String(describing: state))
    self.state = state
    self.state.update(context: self)
}

/// The Context delegates part of its behavior to the current State object.
func request1() {
    state.handle1()
}

func request2() {
    state.handle2()
}

}

/// The base State class declares methods that all Concrete State should /// implement and also provides a backreference to the Context object, /// associated with the State. This backreference can be used by States to /// transition the Context to another State. protocol State: class {

func update(context: Context)

func handle1()
func handle2()

}

class BaseState: State {

private(set) weak var context: Context?

func update(context: Context) {
    self.context = context
}

func handle1() {}
func handle2() {}

}

/// Concrete States implement various behaviors, associated with a state of the /// Context. class ConcreteStateA: BaseState {

override func handle1() {
    print("ConcreteStateA handles request1.")
    print("ConcreteStateA wants to change the state of the context.\n")
    context?.transitionTo(state: ConcreteStateB())
}

override func handle2() {
    print("ConcreteStateA handles request2.\n")
}

}

class ConcreteStateB: BaseState {

override func handle1() {
    print("ConcreteStateB handles request1.\n")
}

override func handle2() {
    print("ConcreteStateB handles request2.")
    print("ConcreteStateB wants to change the state of the context.\n")
    context?.transitionTo(state: ConcreteStateA())
}

}

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

func test() {
    let context = Context(ConcreteStateA())
    context.request1()
    context.request2()
}

} 执行结果Swift Context: Transition to StateConceptual.ConcreteStateA ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context.

Context: Transition to StateConceptual.ConcreteStateB ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context.

Context: Transition to StateConceptual.ConcreteStateA ```

4. 小结

我们对象存在大量状态的时候,当前状态完成不同行为。或者存在很多条件判断对应不同状态,或者是相似状态和基于条件的状态机转换。都可以采用状态模式。比如我们客户端用户有很多状态,我们获取用户不同状态从而跳转不同页面或者一些操作。