00:02
状态模式在实际项目借贷平台的源码剖析,我们这儿找了一个项目,这个项目呢是借贷平台,借贷平台里面呢有一个功能模块,就是这个订单。对这个订单呢,它有这么一个流程是审核发布抢单,对然后呢,这样一个步骤,随着操作不同呢,会改变订单的订单的状态,项目中这个模块呢,实现就会用到状态模式。好,因为这一段代码呢,咱们是从一个项目里面拿出来的,所以说大家呢,直接看源码来剖析就可以了,首先我们看,如果说我们不用。状态模式的话,我们用传统的方案呢,一般来讲是这样子的,有一个if else if else if,也就是说用分分支控制来处理。那大家想,如果我们用分支控制来处理订单的状态的话呢?这类代码难以应付变化。
01:00
就说在增加一种新的状态的时候,我们需要手动的添加if钥,在添加一个新的功能的时候呢,要对所有的状态进行判断,因此代码就会变得非常的臃肿,就是这段代码会变得非常的臃肿。并且呢,一旦没有处理某个状态,就会发生极其严重的bug,难以维护,所以说这种方案呢,虽然可行,但是问题很多,所以说现在呢,我们就可以用我们的状态模式来进行解决,首先呢,我们先来看一下这这一个叫做借贷平台订单的这这一块的业务流程是什么样子的,来我们看一下同学们。打开我们这边的一个流程审批。这边呢,画了一个流程图。OK,这边是一个流程图,我们简单的看一下就可以了,订单呢是从这儿开始,最后到这结束,但是这里面有各种很多的状态。就各个节点的状态都有可能发生,我们首先生成订单,在生成订单过后呢,会有两个流向,第一个我们电审通过了。
02:04
电审通过以后呢,呃,审核完了过后,我们可以定价发布,发布过后呢,如果两个小时没有接单,我们就直接直接进入到已完结状态,并且到订单结束,这是一条线。那么还有还有一种可能性,就是订单一旦生成了,那么审核是不是也有可能是没有审没没有通过呀,就是你这个订单不对,有问题,所以他直接就审核失败,审核失败呢,直接就结束了这个。还有一种就是在这里,当他以发布了以后呢,两小时在这在这个过程中呢,按。呃,接单操作了,有人接单了,一旦有人接单呢,我诶我们就是进入到一个待付款的状态,然后这边呢,待付款这有两个流程,第一种呢,就是有人付款成功,那其他接单就失败,你也进入到订单结束,还有一种就是付款操作,已付款,已付款这边就有反馈下款或者拒贷这么几种操作,因为它是个借贷平台嘛。
03:03
对,就说有有可能你你你我拒贷给你,你因为你的资质不够是吧,我借贷给你,呃拒贷了,所以说这个地方也造成我们这个订单结束,所以说我们可以看到在这个流程里面呢,它的状态非常的多啊,比我们前面讲的APP抽奖状态要多很多。所以说我们来看一下,针对这种情况,如果我们使用状态。我们用状态模式会怎么解决?那下面呢,我们来看一张表。通过这个状态图呢,我们可以加深对它的理解,首先我们看一张表,这张表呢,纵叫做横纵坐标的关系来看,比如说这个整个状态有这么几个状态,订单生成,已审核发布。付款已付款已完结,而这个状态呢,又对应相应的事件,事件有电审通过失败,订单发布,接单接单失败,付款支付失效反馈,所以说他一个正常的流程是这样的一个过程。
04:02
是不是而已完结呢?其实是有好几个情况的,比如说在这个地方就有可能发生一个完结,在这地方也可能订单就结束,还有可能是支付失败已完结,还有一种情况就是我们这个顺顺利利已付款,而且支付也成功了,那这个就是一个反馈。所以说他这个到这个状订单结束呢,它有很多线,从这个表也能看出来,那现在呢,根据我们前面的分析,我们来看一下代码是怎么实现的,那代码呢,我这就不去写了,代码我们已经写好,我们直接拿来看,因为我们这里重点是剖析源码,那么在剖析源码之前呢,我们还是老规矩,给大家画一个类图,再去看源代码,大家会看的比较清晰,来我们画一下这个借贷的。借贷平台的这个类图好,根据刚才的分析,我画一个类图。同样这个类图呢,我们就叫money。啊,借贷吧,叫借借钱嘛,Money。那money它这个图它是怎么画的呢?好,我先给他看一下,首先呢,它会有一个接口啊,这个地方它用的是接口。
05:04
Stay这个接口里面啊,同学有很多方法。那我就不一个个去写了好吗?有很多很多方法。很多方法啊,待会儿我们看语言吧。啊,有很多方法过后呢,注意他这里面跟我们前面不一样,他搞了一个抽象类。Abstract。抽象的一个state,我们是不是前面也有抽象,抽象的状态类呀,他让他去干什么呢?实现这个接口,实现接口呢,这个up STEM,它就提供了所有的默认方法,我写到这里。学啊这个abstract。这个C类呢,OK,它提供了提供了这个接口,所有所有方法的默认实现。方法的默认实现。默认。实现,也也就是说如果说你不去,呃,你你的子类不去实现呢,我这个抽象的state这个类呢,也帮你实现了。
06:06
你就可以用就行了,那下面有哪些类呢?当然很多了,状态类就很多,比如说反馈,其实刚才看到有是不是有个反馈啊,FF,呃,F feed FA什么呢?Bike。State是不是这个就是一个反馈的状态,前面我们是不是看到有一个反馈状态,还有什么状态呢?来是不是我们再找几个,还有一个就是public。PA。Publish。Publish就是发布状态。好。那么这个状态里面,他肯定要去继承他吧。那我再说一句话,就是因为你这个接口里面有很多方法,它下面一个具体的状态类呢,可以有选择的覆盖,这个我们在前面是不是也学过这种类似的111种设计思想,就说你这个接口呢,是把所有的操作都写好了,但是我下面子类。
07:01
就是一个具体的状态指令呢,可以有选择的去实现,而且他也本身应该这样做的。好,所以说我在这儿再写一个注释。就是什么呢,Abstract。Obstract obstra啊,State这个这个类的类,类的子类就是所就是具体的状态类。那么状态内呢,它可以可以根据根据需要,需要有选择的,有选择的去重写什么呢?接口呃,去有选选择去重写抽象类,就是那个它的父类吧,它的父类。户内默的默认实现。默认实现。好,就这么一个道理。那也也就是说,呃,比比如说我们在某个情况下,我们这个publish state呢,要去把你默认实现的方法重新写一遍,如果我我这地方也不能操作,或者我不希望去重写,那我就用你默认实现就完了。
08:08
好的,这个就是他们一个思路,好,那这说完了过后我们再来看他还有什么东西呢。同学们看到,在这段代码里面,它还有一个叫state。I。就是枚举类。这个枚举类呢,干什么呢,会被聚合到,就是我我这个枚举类里面会有你各个具体的这一个状态类的名称,所以说我们可以画一个聚合。OK,画个句号。好,这句话完,最后是不是根据我们前面讲的,应该有一个context上下文对象,这个是肯定有的,我们在前面讲,嗯,在前面讲他的原理图的时候,以及讲APP的时候,是不是我们都出现了一个contact,那那么那个抽象就抽奖里面哪一个是contact呢?相当于我们那个activity,那个活动类是不是好,这里面他会干什么呢?各位同学这个地方也要注意观察,也有个聚合。
09:05
他在这里面是不是根据原先contact会把我们这个state这个通过这个接口,把下面具体的这些个状态都聚合到contact里面去。好,同样道理,他呢,OK,他也会啊,基本上多了一个动作,Contact呢,也会继承他这样子的话呢,你会发现contact也好,Free state也好,Publish state也好,其实都是abstract之类。好,最后呢,我们还有个client端,这个client端呢,它会怎么去用它呢?OK啊,所以说它会依赖,它会依赖哪些呢?它会依赖下面这些具体的。OK。那我需要什么,我就用它就行,这样一个流程,好,这就是我们整个借贷平台的一个审核模块的设计,当然我这只画了两个状态啊,大家根据刚才的分析,状态可不只有两种,很多状态来看,电审、定价、发布,然后呢,还有这个啊,付款是不是这这些都可以看的是一个状态啊。
10:04
因为你的状态很多,所以说我这只画了两个,其实这远远不止两个啊,这还有很多。还有很多,我就没有话那么多了啊,十个亿吧。我在这儿再继承一下。可以了,好,现在呢,我们把这个源码拿过来给大家分析一下,对照这个类图来看看,大家一目了然,好,我把这个代码呢拿过来同学们看一下啊。Money我们直接把它附附到这面来就可以了,诶没有粘过来对不对,好,我在这粘一下。粘过来过后呢,再把这个money放到我们这个包包下面去。咋回事儿啊?没转过来吗?看一下我这边是有的来复制。复制下啊同学们复制,然后呢,粘贴到咱们的这个包包下面去开始一下,好过来了,那过来过后呢,我们来看一下,首先我们看看state的接接口,State的这个状态接口里面是不是有一个,你看到这面有很多很多方法,我就列出来了啊电审电审失败,定价发布接单。
11:06
还有无人接单失效付款,诶同学们发现这些方法都是在我们这个图上出现过的,定价发布就是这个直线,每个直线呢就代表一个操作,而一个方块就代表一个状态,是不是这样子的。OK啊,好,这个就说完了,紧接着我们在看他所有的状态在哪呢?就是根据这个图,我们看看obstra state在哪里,是不是在这啊,同学们有发现他是不是把这个接口实现了,而且他对每个方法都做了一个默认实现,这个默认实现是什么呢?就是抛出一个异常。就说如果你没有去处理,你就不要掉,你掉了就会抛一个异常,这个异常是一个runtime exception,学Java的同学都知道。就是如果你没有没没有去实现,你直接调的话,就会抛出一个异常,这个异常呢,我们可以把信息捕获起来,好,这边都是默认实现写到这。抽象类,抽象类默认实现了什么呀?
12:03
State接口的所有方法。所有方法。那么嗯,这些默认实现的类呢,可以让他的子类去重写,对,就是该类,该类的所有方法,所有方法方法。它的子类,其子类其子,这个子类就是我们所说的具体的状态类。状态类可以有选择的进行重写,可以有选择的,选择的进行什么呀重写。重新重写就可以了,那么我们来看一个吧,那大家看我们就找。Publish state,看看这里面有没有,大家看我这边有个all state,我我没有一个写啊,因为那太多了,所以说我把它全部写在一个文件里面的,就把所有的具体的状态类呢,全部写在这一个文件里面,大家看这边有好多类啊。从那边可以看出来有几个,一个两个,三个四个五个六个,哎,同学们有没有发现这些状态呢?这个是反馈,这个是通用的一个状态,这个是not pay,就是没有付款的一个状态,这个是付款的状态,这个是发布的状态,这个是view review回顾的一个状态是吧?
13:14
OK,大致就这么这么一个东西,那么这样子的话呢,嗯,你你们看到在他的每一个具体类里面,有些方法是被重写了的,有些方法一动,你比如说看这个publish是不是我重写了。重写了这个abstract里面的这个accept order events。对不对。我把他的状态重新设置了一下,如果这个通过,我就把这个contact的状态设置成了一个新的一个叫not ped,这个是不是有点像我们抽奖啊,一旦某个动作做了,就把这个状态改成另外一个状态。这个显然是把。把状态呢,把状态是把状态把当前状态啊,消息把当当前的状态。设置为设置为什么状态呢?就是not PA状态。
14:03
因为这个流程,你整个这个操作流程在不停的变化嘛,当然变成哪个状态,这个根据你的业务流程来说啊。我这喜欢。至于。至于。应该应该变成。哪个状态哪个状态。由什么呢?由流程图流程图来决定。来决定,那就是说你你这个地方,如果accept order问这个事情一旦发生了,那么根据你这方到底应该办成已付款还是未付款,那你自己去根据这个流程图来找就行了,明白这意思吧,那流程图当然是直到你去这个状态的。怎么去修改的,或者怎么去设置的,好,下面他也写了,大家有没有发现obstra里面方法很多,但是我其实只重写了三个方法。是吧,其他方法我们并没有,并没有重写。这就因为我没有重写的希望,就用它默认的。
15:01
OK,好,其他我就不一个看了,但我们把这个看完过后,是不是我们现在应该看一下context,我们看看,看一下context是什么,好,再来看context,诶,你有没有发现contact也有一个state,这个就是我们的当前对象。当前的一个状态,哦,也就是说这个state呢,就代表我们当前状态。那这个当前状态肯定是变化的,它是根据根据我们的业务,呃,流程流程处理。流呃,流程业务流程处理不停的啊,不停的变化。不停的变化,或者叫相应的变化都可以。好,那这里面具体方法叫check event check event make price event等等等等,对不对,这这是他的一些方法,他也干什么呢,他也继承了。这个upright statement。所以他也是在重写这些方法,你看他几乎都重写完了。
16:00
而且这边有个状态好,大致呢,这个就写完,写完过后呢,我们用client来测一下,大家看一下,嗯,我们看看这个大致的一个流程啊,同学们看这里。我先创建了一个上下文对象。创建这个对象。这个对象呢,它会记录当前的状态是哪一个,OK,而且它可以变化,所以说我上来过后呢,你看我把当前状态先设置为一个发布的状态。我这儿啊,将。将什么呢?将当前状态设置为。设置为这个状态publish statement,所以说当我这样一做过后呢,同学们,其实这个状态一设置,如果我来获取这个状态,大家就就能看出这个状态是什么样子的了,好,我们可以来玩一把。因为你已经把它设置成这个状态了,所以说我们可以看context。诶点get,你看这个是不是就把这个状态拿到了,我们输出来看一下,这个状态就应该是发布状态。
17:03
诶,这个不好意思,这写错了system out对不对,我们输出一把。我们输出显然应该就是这个publish STEM运行一下。好,我们可以看到它返回来状态就是published,对不对,OK啊,那现在呢,如果我状态要发生变化,比如说我这个context,在整个这个流程中,它执行了一个accept order event。好,这个一设一设置过呢,我们再来看状态有没有发生变化。诶,你看这一走,他发现它变成了not pay,好很很神奇是吧,当然这个流程到底怎么变,这是你的业务来控制的啊。就根据这个流程图来看,比如说我们又来又来调了context pay order event,你看这个会怎么样呢?好,他又发现变成了配置状态,好,以此类推,以此类推,好下面呢,在这个过程中,如果你需要去要校验有没有问题,好,你可以在content check fire event去看一下流程正确还是失败。
18:04
好,那同学们这个关于。就是。关于我们这一个。是,呃,状态模式在实际项目里面的使用呢,老师就给大家聊到这里,这里面大家应该学习到,就是说如果我们有这样一个状态频繁变化的一种需求,你首先把流程图画一下,然后根据这个流程图分析出来我们的这个状态接口。然后里面有多少个状态好,这个你自己一步把它分析出来,按照老师这个流程去写就行了,对不对,到了哪一步,那个状态变成什么样子。就行。那么你这个时候你就可以很简单,就是把它一调,一个方法,你就可以看到状态怎么变化的,所说这个状态模式呢,应该说还是非常有价值的。好,同学们,关于这个状态模式源码分析就给大家聊到这里。
我来说两句