State Pattern
这篇文章,我们来聊聊状态模式,大家可以好好看看。我觉得这个模式在我们平时工作中的使用场景还是挺多的,而且很有意思。
老规矩我们还是先抛出文章的整体结构,大家带着目的阅读,效果也会更好。同时也能决定是否感兴趣要不要继续看下去。
文章脉络
- APP抽奖活动问题
- 状态模式介绍以及类图
- 状态模式如何解决APP抽奖活动问题
- 状态模式在实际项目-借贷平台的应用解析
- 注意事项和细节
APP抽奖活动问题
这里给出一个需求,大家先思考下如果让你来实现设计,你会如何实现?
- 用户每次抽奖前要扣除50积分,中奖率为10%;
- 奖品数量固定,先到先得,抽完则不让继续抽奖;
- 活动有4个状态:可以抽奖、不能抽奖、发放奖品和奖品领完;
- 活动的状态转换关系图:
状态模式介绍以及类图
基本介绍
- 状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为之间是一一对应的,状态之间可以互相转换。
- 当一个对象的内在状态改变时,允许其改变行为,这个对象看起来像是修改了它的类
类图
对上述类图我们做一个简单的说明:
- Context类为环境角色,用于维护State实例,这个实例定义当前状态;
- State 是抽象状态角色,定义了一系列接口,对应于Context提供的相关接口;
- ConcreteState 具体的状态角色,每个子类实现一个与Context 的一个状态相关的行为;
状态模式如何解决APP抽奖活动问题
- 抽奖应用需要使用状态模式来实现,避免在每个方法出现很多 if-else 判断,而且如果增加状态就得直接修改代码;
- 思路分析,图解类图
- 定义一个状态接口,每个具体的状态都实现它
- 接口有扣除积分、抽奖方法、发放奖品方法,即包含整个业务所有动作
类图我这里给出来,由于篇幅原因具体的代码就不贴出来,都已经上传到 github 上,大家可以自行查阅:
https://github.com/coderluojust/design-pattern
看了类图,这里说明下,就是Activity代表app抽奖对象,它持有一个状态引用,用来保存当前状态,State 表示所有状态的抽象类,定义了整个抽奖app的所有行为接口,比如扣除积分、抽奖等。实现State的有四个具体的状态实现类,他们都实现了抽奖app的行为接口,在不同状态根据实际情况作出对应的操作。 同时具体的状态实现类持有Acticity对象,用来获取所有的状态对象,并且进行当前状态的设置。
状态模式在实际项目-借贷平台的应用解析
上面的学习,相信你已经理解了状态模式的含义以及可以用它来解决我们开始抛出的 App 抽奖程序。 接下来为了巩固学习,方便在实际项目中学以致用,我们一起来看一个实际的借贷平台的应用代码解析。
- 借贷平台的订单,有审核-发布-抢单 等等步骤,随着操作不同,会改变订单的状态,项目中的这个模块实现就会使用到状态模式
- 通常使用 if-else 判断订单状态,从而实现不同的逻辑,伪代码如下:
if(审核) {
// 审核逻辑
} else if(发布){
// 发布逻辑
} else if(接单) {
// 接单逻辑
}
问题分析:
这类代码难以应付变化,在添加一种状态时,我们需要手动添加 if-else 判断,在添加一种功能时,要对所有的状态进行判断。因此代码会变得极其臃肿,并且一旦没有处理某个状态,便会引发BUG,难以维护。
- 使用状态模式完成,借贷平台项目的审核模块设计+代码
还是一样的,这里给出类图,具体的代码全部已经上传到github了。
注意事项和细节
最后我们来一下小小的分析和总结:
- 代码有很强的的可读性。状态模式将每个状态的行为封装到对应的一个类中。
- 方便维护。将容易产生问题的 if-else 删除了,如果把每个状态的行为都封装到一个类中,每次调用方法时都要判断当前是什么状态,不但会产生很多 if-else 语句,很难阅读,而且很容易出错。
- 符合“开闭原则”,对扩展状态开展,对原则状态修改关闭。容易增删状态
- 会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度
- Context 会将行为委托给当前状态对象
- 状态转换可以由 Context 类或者 State 类控制。
- 注意事项和细节: 当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求不同行为的时候,可以考虑使用状态模式。
看到这里的朋友恭喜你,在通往模式大师的路上又进了一步,技能库中收入了我们的状态模式,希望你可以多思考去实践掌握。
本文全!fighting
原创真心不易,希望你能帮我个小忙呗,如果本文内容你觉得有所收获,请帮忙点个“在看”呗,或者转发分享让更多的小伙伴看到。