本文主要讨论状态模式的内容。 简单讲下状态模式是什么? 项目中状态模式的应用场景。
概念
官方解释: 状态模式,是一种行为模式,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。
顾名思义, 状态模式, 就是说一个对象, 可以有多个状态。 且一个行为的触发, 不同状态存在不同的变化。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
项目中实际应用
1. 微信和小程序支付
公司业务,涉及小程序支付情况。且小程序支付过程如下:
这里,我不具体讲述小程序支付的具体过程。 大体流程是
1. 后台应用生成订单信息
2. 小程序发起支付
3. 后台应用等待微信回调,校验支付是否成功。
且公司的业务处理逻辑是:
1. 小程序调用后台,生成订单信息
2. 小程序根据订单信息, 向微信发起支付
3. 小程序调用后台, 查询订单支付情况(如果没有支付完成,则等待,直到支付完成,返回结果)
3.1 等待微信回调信息
3.2 后台应用处理回调信息
3.3 后台应用返回支付结果给小程序
在未加入状态模式之前, 回调处理逻辑如下:
1. 订单信息是否存在, 否, 则返回订单信息不存在, 不继续处理; 是,则继续下一步。
2. 订单是否未发起状态, 否, 则不处理; 是,则进行下一步;
3. 处理订单信息
小程序查询支付结果接口,逻辑如下:
1. 判断订单是否存在, 否, 返回订单不存在,支付失败; 是,则继续下一步。
2. 判断支付订单是否失败, 是,则返回支付失败; 否, 则继续下一步。
3. 判断支付订单是否是未提交和支付中状态, 是,则等待 ; 否, 则继续下一步。
4. 判断支付订单是否支付成功, 是,则返回支付成功; 否,则支付失败。
综上所述, 状态判断较多, 逻辑较为复杂, 导致后期维护和开发成功较高。
所以,后期为了简化代码, 同时,提高请求速度。 我们考虑加入redis作为订单信息缓存。并将订单信息分为四种状态:
1. 生成订单(UnCommit状态)
2. 支付中状态(接收到回调信息,但是还没有处理完,Paying状态)
3. 支付成功(Success状态)
4. 支付失败(Fail状态)
并规定状态可行性方向
调整之后, 流程逻辑如下:
1. 生成订单信息的时候, redis中写入一个UnCommit状态订单,若加入失败,则返回支付失败。
2. 在收到订单回调信息的时候, redis中加入Paying状态(在回调接口最开始,还没有开始处理具体逻辑代码的位置),若状态加入失败,则不处理订单回到逻辑。
3. 在订单处理完成, redis中根据实际情况加入Success或Fail状态,若加入失败, 则返回失败。
回调函数逻辑如下:
1. 得到redis中订单信息(若订单不存在,则从数据库中查询, 若也不存在,则返回状态为空的订单), 进行paying状态提交, 若状态提交返回为空, 则不处理。
2. 继续处理请求, 若支付失败, 进行Fail状态提交。 若支付成功,则进行Success状态提交。
小程序查询支付结果接口,逻辑如下:
1. 得到redis中订单信息, 查询订单状态。若不存在,则从数据库中查询。 若数据库中也不存在, 则返回订单状态为空的订单
2. 若订单状态为空, 则返回支付失败; 若支付为失败,则返回支付失败。 若支付成功, 则返回支付成功。
3. 反之,若支付未结束(Uncommit和Paying状态), 则等待。 将线程挂起, 并将该线程加入超时线程池。
4. 若在超时时间内,未完成订单处理, 返回支付失败, 请稍后刷新,更新订单信息。 若未超时, 在订单状态更新为Success或Fail状态的时候, 唤醒线程,继续完成支付结果查询接口。