请编写程序完成app抽奖活动
具体要求如下:
1) 每参加一次活动要扣除用户50活动积分。中将概率为1/10。
2) 奖品数量固定,抽完不能再抽奖。
3) 活动有4个状态:可以抽奖、不能抽奖、发放奖品和奖品领完。
4) 活动的四个状态转换关系图如图所示:
状态模式的基本介绍:
1. 在状态模式(State Pattern)中,它主要用来解决对象在多种状态转换时,对外输出不同行为的问题。状态和行为是一一对应的,状态之间可以相互转化。
2. 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来是像是改变了其类。
状态模式类图:
对原理类图的说明即状态模式的角色和职责:
1) Context:是环境对象角色。它用于维护State实现类ConcreteState实例,这个实例定义当前状态是什么样子。
2) State是一个抽象状态角色,它是一个抽象类或者接口,定义了一个接口封装与Context的一个特点接口。
3) ConcreteState:具体的状态角色,每个子类实现一个与Context的状态相关的行为。
状态模式完成抽奖活动:
1) UML类图:
关键代码:
package com.xia.designmode.study.statepattern;
/**
* 状态模式-状态接口角色
* */
public interface State {
//扣除50积分才能抽奖
public void dedPoints();
//是否抽奖成功
public boolean raffle();
//发放奖品
public void accPrize();
}
package com.xia.designmode.study.statepattern;
/**
* 状态模式-context角色 Activity实现抽奖
* */
public class Activity {
//活动当前状态,它是变化的。
private State state;
private int count;
private State canReffleState;
private State nonReffleState;
private State dispenseState;
private State dispenseOutState;
public Activity(int count) {
canReffleState=new CanRaffleState(this);
nonReffleState=new NonRaffleState(this);
dispenseState=new DispenseState(this);
dispenseOutState=new DispenseOutState(this);
//初始化当前状态和奖品数量
this.state=getNonRaffleState();
this.count=count;
}
private State getNonRaffleState() {
return this.nonReffleState;
}
//扣除积分,调用当前状态扣除积分
public void dedPoints() {
state.dedPoints();
}
//抽奖
public void raffle() {
//如果当前的状态是抽奖成功,则,发放奖品
if(state.raffle()){
state.accPrize();
}
}
public void setState(State state) {
this.state = state;
}
public State getCanReffleState() {
return canReffleState;
}
public State getNonReffleState() {
return nonReffleState;
}
public State getDispenseState() {
return dispenseState;
}
public State getDispenseOutState() {
return dispenseOutState;
}
public int getCount() {//每次领取完成奖品后,count要减掉1
int curtCount=this.count;
this.count--;
return curtCount;
}
}
package com.xia.designmode.study.statepattern;
/**
* 状态模式-context角色 Activity实现抽奖
* */
public class Activity {
//活动当前状态,它是变化的。
private State state;
private int count;
private State canReffleState;
private State nonReffleState;
private State dispenseState;
private State dispenseOutState;
public Activity(int count) {
canReffleState=new CanRaffleState(this);
nonReffleState=new NonRaffleState(this);
dispenseState=new DispenseState(this);
dispenseOutState=new DispenseOutState(this);
//初始化当前状态和奖品数量
this.state=getNonRaffleState();
this.count=count;
}
private State getNonRaffleState() {
return this.nonReffleState;
}
//扣除积分,调用当前状态扣除积分
public void dedPoints() {
state.dedPoints();
}
//抽奖
public void raffle() {
//如果当前的状态是抽奖成功,则,发放奖品
if(state.raffle()){
state.accPrize();
}
}
public void setState(State state) {
this.state = state;
}
public State getCanReffleState() {
return canReffleState;
}
public State getNonReffleState() {
return nonReffleState;
}
public State getDispenseState() {
return dispenseState;
}
public State getDispenseOutState() {
return dispenseOutState;
}
public int getCount() {//每次领取完成奖品后,count要减掉1
int curtCount=this.count;
this.count--;
return curtCount;
}
}
package com.xia.designmode.study.statepattern;
/**
* 状态模式-客户端
* */
public class Client {
public static void main(String[] args) {
//创建活动对象,奖品池有5个奖品
Activity activity=new Activity(5);
//连续抽奖300次
for(int num=0;num<300;num++){
System.out.println("参加第"+(num+1)+"次抽奖");
//第一步骤:扣减积分
activity.dedPoints();
//第二步骤:抽奖
activity.raffle();
}
}
}
状态模式在实际项目借贷平台应用源码分析:
1. 借贷平台的订单,有审核-发布-抢单等等步骤,随着操作的不同,会改变订单的状态,项目中的模块会使用到了状态模式。
2. 通常使用ifelse来判断订单的状态,从而实现不同的逻辑,伪代码如下:
3. 流程图如下:
4. 类图:
状态模式注意事项和细节:
1. 代码具有很强的可读性,状态模式将每个状态的行为封装到对应的类中。
2. 方便维护,容易产生问题的ifelse语句删除了,如果把每个状态的行为放到一个类中,每次去调用一个方法都要判断当前状态是什么状态。不但会产生很多if-else语句,而且容易出错。
3. 符合开闭原则,容易增删状态。
4. 会产生很多类,每个状态都要有一个对应的类,状态过多时会产生很多类,加大维护难度。
5. 当一个事件或者对象有很多种难度时,状态之间会相互转换,对于不同的状态要求有不同行为时,可考虑使用状态模式。