00:01
状态模式解决APP抽奖问题,那前面呢,我们已经把这个需求说的比较清楚了,这边大家可以看到就是我们。这一个APP抽奖的四个状态分别是可以抽奖发放奖品。奖品领完和不能抽奖,那同学们可以看到他们之间转换的一个条件,这地方也画的比较清晰,那现在呢,我们再去。看这个代码之前呢,我们先来把它这个APP需求的类图给大家分析一把。对,把他的角色分析清楚了,过后再去看代码就变得比较清晰了,那打开我们的eclipse,我们新建。一个类图来走一个。好,我们就叫APP。那这个时候我们应该怎么去设计呢?同学们,首先根据前面分析,应该有个state。接口对,那这个接口里面有哪些行为呢?根据我们这个类图,首先看是不是它有一个扣积分的动作,所以说我要在这里呢,加上一个方法。
01:10
啊,加上一个加对加上一个操作。Theduce。The是什么呢?Money?啊,比如说这个扣他的钱,这是一个,还有一个是不是有个抽奖的呀,同学们看我们这边是不是还有一个点击抽奖的动作啊,那么我们写一个。方法。写一个方法叫rapper。对,Rap写到这raf。Rap呢,这个单词就是代表抽奖的意思,还有一个是不是要领取奖品呢?如果抽中了,是不是我们要去领取奖品,因此呢,我在这写个dispens。This pen?Enp是什么呢?我们的PRIZE0,我们的奖品好的,那这个地方应该是返回一个布尔值对吧,因为它有没有抽中,应该是返回一个布尔值,不定值。
02:07
好,这是我们的状态接口,那同学们也知道我们这里一共有几个状态,根据刚才的分析,有四个状态,因此呢,我们这边至少有四个类,至少四个类,哪四个类呢,我们写一写,第一个呢,我们认为是,呃,不可以,还不可以抽奖的一个状态。No state。是不是我们前面讲过,在初始的时候,他是一个不能抽奖的动态是吧,所以说呢,我让他去实现这个接口,第一个就OK了。当然这里面既然它实现了这。State接口,所以这里面三个方法它都要怎么样实现值,这个我就不再去画了啊,这是第一个状态类,第二个是不是还有一个可以抽奖的,看看rap。什么呀,State,我们又是一个具体的状态之类,于是乎让他也去到这个地方实现啊,别写错了。
03:10
那这个线是不是也画错了呀?实现。好,没有问题,还有什么?同学们想一想,是不是还有状态呀?我们还有两个状态,还有一个叫去领取奖品的状态,Dispens。什么呀?这个状态就是同学们看到这的叫发放奖品,发放奖品OK啊,那同样我们也去实现这个状态接口,还有最后一个状态,同学们还有一个状态呢,就是奖品领完了没有装,没有东西可以领了,我写个叫dispens。Somepens。什么呢?Out,没有了,对。State。对,这样写就可以了啊,这个地方咱们叫dispense state。
04:01
标合力。好,这样就OK了。同样我们也让这一个类去实现我们的。这个状态接口就写完了,那大大家再再多说一遍哈,就是这个接口里面的三三个方法呢,它下面都要实现。但是我要清晰的告诉大家,就是你不同的状,不同的状态之类,对这些方法是不一样的。待会儿呢,从代码里面能够体现出来。从代码里面可以体现出来,呃,除了这个,是不是我们还有一个特别重要的东西啊,是不是还有一个活动就是activity activity。Activity就是一个活动活动类这个这个活动类呢,你你们可以认为是在这里边会干什么呢?OK啊,他跟我们的这个状态。哎,也就是说这样理解就是no。
05:00
No state can state,还有dispens,他这里面会跟他是一个什么关系呢?就是相互关联的关系。也就是说在active里面,它会有。这个no rapper state,因为他有管理这些状态嘛,这个是一个活动,所以他这跟他们之间都有关联的。就都有关联的,就是你中有我,我中有你所说大家看我这画的是关联关系,我在这呢,说一个说明,就是这个活动啊activity activity干什么呢?这个类,这个类含有含有含所有的所有的状态。状态对象。因为他他的这个活动的状态在改变,那我根据实际情况就就能设置当前的状态是哪一个,同样的道理,我们发现呢,每一个状态就是每一个具体的状态之内,也可以获取到我们这个活动这个对象。
06:04
对不对,他们之间是联系的,所以说还有一点呢,各个各个什么样状态。状态之之类也可以。也也含有,含有什么呢,Activity。TVT的这个对象,所以说他们之间是一个什么关系呢?是一个关联的关系。好,最后呢,我们还需要一个client去调用它,是不是还需要一个client调用它。那调用的时候呢,我肯定会去依赖他嘛,主要是通过它,还有它去依赖就可以了。好,同学们,那这这个关于我们要说说所说的APP抽奖问题的类图,我们就说完了,那大家看这里面的代码比较多啊,关系其实已经捋清楚了,状态有三个方法,里面有是下面有四个具体的。状态之类,然后呢,有个activity,这个activity里面呢,跟每一个状态都是有关联的,也就是说在这个activity里面,它包含所有的状态对象。
07:06
好了,那现在既然如此,我们现在直接看一下代码就可以了,好,这个我就不去写它了,来,我把APP里面代码给他拿过来看一下。就对照我们这个类图来看,没有什么难度哈,来,那现在呢,我们建一个干脆就直接放这吧。干脆就直接放这好吧,也没有什么太多难度,我把这些类的刀给切一下。切一下就可以了,待会儿呢给大家演示一把,各位。来,我把这一包都先切好。转换成我们现在对应的。对应的这个位置的包就可以了。No rap。来,走到这儿来。好,紧接着呢,还有一个rap。抽奖活动。好的,我们一个个看啊,这是我们状态接口。
08:00
来对照刚才老师画的这个类图,我们来一个个看,首先我们看这个接口,来一一点一点的给大家做一些注释,帮助同学们理解哈,帮助同学们理解,我们先看state,嗯,这个state是个什么东西呢?刚才已经讲了,它是一个状态接口。他这个是个抽象啊哦,我这写的是抽象类。不是接口,那跟我这分析,我们在前面写的这个地方是个接口,对不对,这方是个接口,它这是抽象内,那抽象类其实也可以,因为我们讲过,作为抽象层来讲,接口可以,抽象类也可以说这个呢也并不是特别矛盾的,我们在最先前就说过,从设计模式来看呢,接口类都行,那我最好最好还是把它改一改,最好跟我们保持一致,好吧,我改一下没关系的。啊好,我重新写一个state,它叫它是个抽象类嘛,那我把它改一下好的。
09:04
那我在这儿呢?放一个这个好吧,这个地方我们。也把它粘过来。再来一个。也把它粘过来好,粘过来过后呢,我们把这些方线都改一下,那让他这边就不是实线了,把这个线重新画一下就可以了,没关系。好的,呃,我我把这个也拿掉,这个线这个我就不要了,好吧,拿过来,那把他们的关系捋一捋,这这个地方就变成了什么样,继承。没问题吧,继承其他关系一样,Activity呢,也会去跟我们的各个具体的状态对象进行一个关联,这个没问题,同样这个client client呢,也会以来到state。好,这个这样就OK了。好,现在呢,我们来回头说这个,这是一个抽象状态,抽象类没问题,下面呢,我们这有三个方法,哪三个方法,第一个是扣除积分。
10:06
扣除积分,一看就知道是在做什么事情,扣积分我们是不是要扣50个积分呢才能去抽奖,这个是干什么呢?大家看这是。这个rap就是是否,他用来看是否抽中了奖,是否抽中奖品。抽抽中。抽中奖品没问题吧,奖品下面这个呢,这个方法就是说发放奖品的。发放奖品。那大家想。奖品。那以发放奖品,我们奖品的数量就应该减少,好,这是一个抽象类,紧接着我们来看它下面对应的四个具体的状态之类,我们一个按顺序来看,首先第一个。好,我们来看看这个类,这个类它做了哪些事情呢?好,首先我们确定它的状态是,它是什么呢?它是不能抽奖的状态。
11:07
不能抽奖的状态也很好理解,那么这个不能抽奖的状态,大家有发现他把这个activity。放到这里面去了,所以说在这个具体的。状态子类里面,它其实引入了我们这个活动,对不对,那这边下面这个这个构造器我就不讲了,这是。扣除我们的积分。在不能抽奖的,在不能抽奖的状态是可以扣积分的,假定我们这提示扣积分成功,一旦扣积分成功,我们就把这个状态。因为这个activity呢,它里面记录了当前的状态是哪个,也就是现在这个当前状态呢,就被修改了,那我写一下。写字啊。当前状态。可以扣积分。扣积分,为什么他可以扣积分,因为你现在是不可以抽奖的状态,从这个示意图,大家再看一下示意图是不是在不能抽奖的时候是可以扣积分的。
12:09
是可以尝试去扣积分的,是不是?所以说我这写的是当前状态是可以扣积分的,OK,扣除后注意听扣。扣除后状态将状态。嗯,把扣说把这个状态变为,或者设置成,设置什么状态呢?设置成可以抽奖的状态。可以抽奖状态,注意啊,这里我假定,这里我假定扣除50个积分成功了,也就是说我没有去把这个积分这个校验写写到里面去,大家看我从activity里面得到一个可以抽奖的状态,设置到这个activity里面去。也就是说这个activity,当activity当前的状态就变成了可以抽奖的状态。可以抽奖。
13:00
抽奖的状态。OK,没问题吧,下面呢,这个地方,这个地方呢是表示。这个地方是代代表抽奖。那么这个时候你你能抽奖吗?就说在你还是注意听。在你还在这个不能抽奖的这个状态时,你们发现他是不能去抽奖的,因为他还没有还没抽奖,也不知道他抽有没有抽中是不是,所以在这个状态呢,他是不能抽奖的当前状态。当前状态。不能抽奖。大家。大致明白什么意思吧,不能抽奖。为什么不能促销,因为你现在是在一个不能,呃。呃,就说你现在还在一个不能抽奖的状态,所以说你现在还不能去抽奖,你先要扣积分才能去抽奖,紧接着我们再来看这fans,你现在肯定连奖都没抽,所以说在这里呢,在这个状态下面也是不能发放奖品的,所以说我就再写一句话。
14:05
就当前状态。不能不能,怎么样不能。发放奖品,他是不能发奖品的。发奖品的。是不是,所以说我在这,如果你在这个状态下,也就是说你在这个状下去调用我们dispens price,我们会返回一个不能发放奖品。那我们再来回头理解这句话就应该比较清晰了。大家还记不记得我在这儿说过这样一句话?当一个对象的一个对象的内在状态变化的时候,允许改变其行为,这就让对象看起来好像是改变了小类,也就是说我们刚才讲过。这个。这个。状态和他的行为是一一对应的。那这句话落实到老师写的这段代码里面,大家就应该比较清晰了哦,如果是在一个不能抽抽奖的,不能抽奖的状态的情况下,我们是可以扣积分的。
15:14
但是呢,我们还不能抽奖,我们也不能发放奖品。OK,就是这个意思,那其他的类呢,我们。也就如法炮制来理解了,好,我们再来看下一个类,也就是看rapper state,那这个里面呢,其实也要实现这几个方法,是不是首先。如果在能够这个是能抽奖的状态了,是可以。可以抽奖。的状态,那大家想一想,他已经到能够抽奖的状态了,请同学们思考。是不是这个时候咱们就不要在不能再去扣分了吧,因为你到这个状态的时候,你你再去扣分,我们应该提示他一句话说你已经扣过积分了。
16:04
但是这个时候能不能抽奖了,可以抽奖。好,所以说我这提示正在抽奖,请稍等,而且我们这个代码里面写的很清楚,你看我再让它随机生成一个零到九的数。那么假如返回是一个零,我们就认为抽中奖品了。他一旦抽中奖品,我们就把这个activity,这个activity就是有点类似于我们前面讲的contact。我们就把activity的状态设置为什么呀,可以去领奖品的状态了。是不是,然后返回一个抽就说抽中了。那如果说它随机产生的这个number并不等于零。也就是说他有只有10%的可能性抽奖,那么我们就说很遗憾没有抽中奖品,然后把这个状态就改成了另外一个叫no rap,就是没有抽中奖品的一个状态。
17:00
改成不能抽奖的状态了。明白这个道理吧,说他状态呢,总是在不停的变化,而这个不停变化的状态呢,会直接设置到我们这个activity。好,大家大致明白了,好,如果在这个状态下面去,呃,Dispens price呢,就说没有中奖,不能发放奖品。因为这个时候你还你还你还没有去抽,抽中奖嘛,只有在只有在什么能够领奖品的时候,我们才能发放奖品,说这边提示的是这样一个含义,好,我们把这个地方稍微的整理一下,OK啊,写到这里是已经扣。已经扣除了,扣除了积分。积分不能再扣了。不能再扣,因为你你这个扣完了过后,我就要去抽了奖,你才能进入到一个不能抽奖的状态,才去扣积分吗?好,下面这个地方什么意思呢?同学们注意听啊,这个有点绕,有点绕,这个地方是什么呢?这个地方是可以抽奖了。
18:01
可以抽奖。可以抽奖好,抽完了后,抽完奖后,抽完奖后根据情况,根据实际情况设置新的状态。或者是改变成新的状态,改成新的状态能理解吗?啊,改成新的状态,大家应该能看懂。好,这如果在这种这个能够可以抽奖的状态的情况下,我们去调dispens,我们提供的信息就应该是什么呢?就应该是同学们看到的这句话。就是不能发放奖品,在这个情况下,我们是不能发放奖品的。发放奖品。OK。好,大致这个就写完了,好现在呢,我们又把这个类写完,现在我们来看dispense state。对,首先我们来说一下,这是一个什么样的状态,好,同学们跟上我的思路,这是一个怎样的状态呢?这是一个发发放。
19:03
发放奖品。奖品的状态。也就是我们这个图里面放的。这个状态,因为他已经抽中了,我们就要给他发放奖品,那发放奖品里面看是不是他也把我们这个activity聚合到。它的属性里面来了下面一样的在这个地方。当他已经进入到发放奖品的状态,是不能扣积分的了,你在这再去调,那不能掉了,好,那这地方也不能抽奖了,因为他刚刚抽过,好这个地方看发放奖品了,这。这个地方就发放奖品。对吧,发放。这个地方应该是我们的哪个代码呢?发奖品,发放奖品。那发奖品,呃,我们首先要去判断一下,呃,这个奖品你现在还大不大于零,就就说你你得有啊,啊你你已经进入到发放奖品状态了,你还得看一下你现在还有没有奖品,如果大于零,我们就说公起中奖了,然后呢,把这个状态重新设置为不能抽奖,也就是说从这个状态回到这方,因为我是counter大于大于零嘛。
20:15
现在可以给你发奖品了,发奖品但是呢,我得判断一下大不大于零,如果大于零我就给你发了,过后我回到这个状态,好,同样的道理,再看下面代码,如果说,呃,如果说什么呢?如果说你虽然已经抽中了,但是很遗憾我没有奖品了。所以我就告诉他很遗憾奖品发完是吧,就这么一个意思,那如果奖品发完过后呢,我应该把这个状态设置到什么地方去了,大家大家看这个图啊,因为这个地方我发现呢,他已经没有,所以说就设置到奖品领完的状态,一旦进入到两奖品领完的状态,那我整个这个活动就结束了。就是谁也不能再抽奖了。大家明白我的意思吧,注意认真听啊,也就是说这个时候我就把设置成了get一个dispens output,这个时候把状态直接设置为奖品发送完毕,那这个时候呢,像以后后面后面我们就不可以不可以再抽奖了。
21:12
因为没东西了嘛。好,这是我们这个叫做发放奖品的状态,还有一个最后一个我们再来看最后一个,还有一个叫dispense out state,我们把这个这个类呢,你看一下来,我们先说一下这个状态是一个怎样的含义,这个是奖品。啊,奖品怎么样发放,发放完毕的一个状态。对,那前面都一样不说了。这个时候他在想,因为这时他已经进入到这个状态了,就是我们的activity已经进已经把状态设置成奖品领完的状态了,在这个状态下面,你会发现所有的红豆通通不能再做了。也也也就是说我说明一下当当我们的activity。
22:06
TT。已经设置成了,或者改改变成改改变成了,当这这个状态。那我们后面的所有的活动都不能再参加了,及活动结束,及所有的及所有的呃,抽奖活动抽呃就相当于说抽奖活动结束了。抽奖活动结束。就不能再玩了,这个时候你不管去掉扣积分还是a rap,还是去领奖品,通通提示奖品没有了,请下次参加,就这次活动结束了。这次活动结束了,好,那现在呢,根据这个分析,我们是不是把这边五个。就是一个抽象类,还有四个具体时间内写完了,最后是不是activity,我们要看一下了,这里面activity呢,它取在我们代码里面写着rub。
23:03
Activity,这个就是抽奖活动。那大家有没有发现在这里呢?我们这个state就是代表当前状态,注意这个state呢,表示的是当前的这么一个状态,能理解好就是当前表示。表示我们这个活动活动当前的不着急啊,当。当。当前诶。当前的状态。是变化的是。是变化的啊,在这个活动中它是经常变化的,这个count呢,表示我的这个奖品的数量。奖品数量。这个可以初始化。初始化为零,但是我们构建这个活动的时候,我们可以直接给他,给他来一个奖品,OK,下面这几个同学们看到我们这个活动里面包含了四种状态,它会经常发生变化,我们可以设置成啊,就是说下面这四个属性。
24:05
四个属性表示表示四种状态。那也就是说,也也就是说我们这画的图里面这些看到没有lo state can state dispens state,还有dispen dispense outt,都会被聚合到我们这个activity。因为你我得知道你到底是哪个状态啊,我四种状态都要管理你,下面大家看这是一个构造器,这个大家一看就明白了,构造器,构造器呢,它会初始化我们奖品的数量。和当前的状态会干什么呢?会注意听,它有两个作用,第一个。第一个啊,它会初始化。初始化当前的状态。那大家知道我在前面讲课的时候,其实我已经说过了,他刚刚开始的时候,应该是初始化成一个不能抽奖的状态,所以说直接把这个state设置成什么呢?设置成一个no rap state,而这个get呢,其实就是get他的。
25:08
也就是说我事先已经有四个状态了,根据你的需求,我不停的变化就行了,所以说初始化成初始化当前状态是什么呢?初始化。当前的为。喂。状态。为什么呢,OK。为这个no rubber statement,即不能抽奖的状态。不能抽奖的状态有点绕是不是?同学们,呃,其实我觉得这个设计模式还是挺挺不错的哈,然后呢,还要初始化什么呢?还要初始化我们奖品的数量。这个数量呢,根据你的需求来给就行了,好大看如在这个状态下面,你如果调的是。要扣积分。扣分。那么我就调当前的这个状态的,第四,呃,Mass就干什么调用调用当前状态的。
26:08
下面一样的道理。对,下面一样道理,下面这个是抽奖。抽奖,那首先我要判断你是不是抽奖成功了,如果抽奖成功了,我就用当前这个状态去看看能不能领这个奖品。是不是OK,那这个就是说,如果。如果当前这个状态是抽奖成功了,因为他会返回一个布尔值吗?如果当前的状态是抽奖成功。抽奖成功,那么我们就去领奖品,领取奖品。是吧?领取奖品,但是你这个状态能不能领奖品,那就根据你的代码来走,下面这个是不是也是这样的,下面我就不说了,全是一堆get set。好,大家可以看到,在这里呢,我写了一段代码。每get一次count,我先把这个get,我先把这个返回去,同时还要减减,注意我看大家注意看我的代码啊,这里请大家注意,请大家注意每领一次场奖品,每领。
27:14
零。每领取领取一次奖品。奖品。呃,奖品,那么他的这个count要减减。抗德要检,你看我是怎么处理的,我先把这一个数奖品的数量先保存起来,然后看到减减减减完了过后把当前的一个拿过去,因为我假,假如你现在count还有一个一是不是我返回是一,一大于零是可以领的。但是你下次再来判断就已经变成零了,那就不能再领取了,你理解这意思吧?好的,下面就不再多说了啊,就是各种状态的设置一样的,好,同学们,这个整完了以后呢,我们来玩一把。下面呢,我们就差最后一个了,用这个client去玩一下这个抽奖游戏,来,同学们跟上我的思路。
28:02
很简单,我们在这里呢,我们创建了一个活动对象,奖品呢,有假设奖品里面我们就设了一个,然后我抽了多少次呢?抽了300次,假如我抽了300次啊。我说诶第一次抽奖品,然后呢,我先去扣积分,扣完积分过后我就去抽奖。但是他能不能抽奖那就不知道了啊,能不能抽中也也是不知道的,来我们这样子,我们先来玩三次运行。好,我们看这边提示信息。他说,第一次抽奖扣了50个积分,你可以抽奖了,正在抽奖其中很遗憾没有抽中,第二次你又没有抽中。啊,第三次还是没抽中,所以说我们这个运气很不好,就说我们抽了三次呢,因为我们抽奖的概率只有呃,10%是能够抽抽中的,所以说三次里面一次没抽中,其实也是可以理解的,我把这个量放大一点,比如我变成30好吧,变成三十来,这应该抽中一次了,来看同学们可以看到。
29:03
我们第一次没有抽中,遗憾,第二次没有抽中,第三次没有抽中,第四次没有抽中,第五次没有抽中,第六次也没抽中。往下走。诶,同学们看。我们在第第几次啊,好,同学们看这里。在这里,在第十次。在第十次。我们抽中奖品了。菜地十次我们抽中奖品了,那第一次第十次再抽中奖品过后呢,11次又没有抽中,12次又没有抽中,但是同学们看到哦,注意啊,12次的时候大家有没有发现,注意听这句话很关键的一个地方啊,在12次的时候去抽抽,他去抽抽奖的时候其实他抽中了。他抽中了12次的时候呢,抽中了,但是在第12次他抽完了过后,他却发放,发现奖品已经。
30:00
他发现奖品已已已经发送完毕了,在我们代码里面,大家还记不记得,一旦发现奖品。发送完毕了,就会把状态设置成。奖品领完。还记得吧?那么我们来追一下这个代码。追一下这个代码就是。在领取奖品的地方,应该是在这个位置吧。大家有发现号。我们应该是在这领奖品,大家看,这用代码很关键的地方大家看。当这个人他抽中奖品,他去取的时候呢?他发现他虽然中了,但是没有奖品,所以他就说很遗憾奖品发完了。同时。同时注意听这句话,同时他把这个状态设置为奖品发送完毕就没有了。也就是说现在activity已经变成了哪一个状态呢?就是奖品发送完毕的状态,所以说你们有发现从第12次以后,你们看他再想去抽的时候,直接就提示奖品发送完毕。
31:11
就不会再去让他去抽奖了,已经直接打回去了,所以说这个状态模式呢,在这个地方就得到修改。大家看这是一个很有很有意思的情况,所以说我们这个状态呢,在他不停的抽奖的过程中,最终他会到这个位置去。那么我们的这个就结束了,其实同学们可以在在这个地方再写一句话,如果奖品结束了,我们再提示一句话,就加一点动作,果进入到奖品领完的话呢,我们可以干什么呢?直接退出这个程序,提示他程序游戏结束,你们知道这句话怎么加吧。其实挺简单的,你只要进到这个地方来,对吧,把它设置成这个状态。那么我们可以在这帮直接退出就完了。这个由你来决定啊,我就不去写这个代码了。
32:01
或者是或者是怎么样呢,在他嗯,发现自己状态已经变成这个的时候,咱们就退出程序也是可以的。对吧。发送,发送完毕,没有了,可或者这样子简单提示一句话。对不对,然后你这直接提出游戏结束。对吧,怎么说抽奖。抽奖活动结束了。抽奖活动结束,我们直接退出程序,这是可以的是不是,诶这个咱们就不这样退出了system。Z0。是不是这样也是可以的,也是可以的。好好,那么我们可以试一下,看看这样子能不能得到我们想要的一个结果呢?好,来玩一把。好同学们可以看到,诶,你看这到第15次的时候,他呃,15次他抽奖抽成功了,然后呢,这边方。恭喜抽奖了,还有一次是正在抽奖,请稍等,很遗憾没有这个时候正在抽奖,请稍等,奖品发完了,发完了我们结束。
33:06
好,这是我给大家提的一点,呃,改进哈,改进当然,呃,如果站在这个角度上呢,我们就不去改它了,我还回到原先这个位置。把这个代码呢,我们还改回去好吧。各位。好,我花了一点时间,就把我们整个用状态模式来解决APP抽奖的代码做了一个详细的介绍。呃,其实说说白了吧,只要大家把这个状态图看懂,然后呢,再把哪个呢,再把我们这画的。嗯,就是这个类图看懂我觉得应该没有太大的难度。因为这个代码太多了,所以说我就直接拿来把代码进行一个分析好,同学们那关于使用状态模式来解决APP抽奖问题的内容,我们就给大家介绍到这里。
我来说两句