序言
最近项目的首页弹窗进行调整,要加几个弹窗,而且还是要按顺序弹出的。原来的只有悬浮窗权限弹窗和存储权限弹窗,用一两个标志位就可以解决了。现在加了隐私协议弹窗和青少年模式弹窗,变成了四个弹窗,如果还是按照原来的方法,即加标志位解决,逻辑机会变得非常复杂,也很容易出 Bug.
经过调研,发现可以用 state 转态模式去解决这个问题。
下面我们先看看 state 转态模式
State 状态态模式
意图
State is a behavioral design pattern that lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类
State 模式与状态机有着类似的地方,都是从一个状态切换到另一个状态
State 模式的类图
参与者
Context 上下文
- 定义 Client 感兴趣的接口
- 维护一个 ConcreteState 子类的实例,这个实例是当前的 state
State 状态
定义接口以封装与 Context 的一个特定状态相关的行为.
ConcreteState 具体状态类
每一个子类实现一个与 Context 的一个状态相关的行为
协作
Context 将状态相关的请求委托给当前的 ConcreteState 对象处理
Context 可以将自身作为一个参数传递给 state, 让 state 可以访问到 Context
Context 是 client 使用的主要接口, 一般情况下 client 不需要直接与 state 打交道
Context 或 ConcreteState 子类都可以决定 next state, 以及设置转态转换的条件
适用性
一个对象的行为取决于它的状态,并且必须在运行时刻根据状态改变它的行为
一个操作中含有庞大的分支条件,并且这些分支依赖该对象的状态
实现过程
确定 Context 上下文
确定 state 的接口
继承 state 接口,实现具体 state 类
在 Context 中,用一个成员变量指向当前的状态,并且提供对外方法可以设置这个值
- 初始化一个开始的 State 并传进 context。
State 模式在 Android 中的应用
回到我们文章开头的问题,我们想要把弹窗顺序的弹出,刚好和 state 模式中的状态切换是一致的。 第一个弹窗弹窗后,切换到另一个状态,下个弹窗是否弹出,完全取决于所在的状态。这样就可以减少一堆的标志位判断了。
这样说比较抽象,可以结合下面的例子来看;
需求:
在第一个弹窗之后,点击确认或者取消;
弹窗第二个弹窗,点击第二个弹窗的确认或者取消,弹窗第三个弹窗;
点击第三个弹窗,结束;
StateDialog 的设计
下面是类图
DialogContext 是上下文,用来存储当前 DialogState,在 nextDialogState 方法设置下个状态
1 | public class DialogContext { |
BaseDialogState 是做弹窗的基类,提供 nextDialogState 和 handle 方法
在 handle 方法里面进行自身逻辑的处理
1 | public abstract class BaseDialogState { |
IDialogStateManager 和它的实现类 DialogStateManager 是 Activity 连接 DialogContext 的中介,相当于 Client。
1 | public interface IDialogStateManager { |
调用过程
在 MainActivity 调用 DialogStateManager,进行管理
调用的时序图
1 | public class MainActivity extends AppCompatActivity { |
最后我们看调用的效果
完整的代码已上传到 github
参考
- 《设计模式 可复用面向对象软件的基础》第 5 章, 5.8 State (转态)
- design-patterns: State