状态模式
APP抽奖活动需求
请编写程序完成APP抽奖活动 具体要求如下:
1.假如每参加一次这个活动要扣除用户50积分,中奖概率是10%
2.奖品数量固定,抽完就不能抽奖
3.活动有十个状态:可以抽奖、不能抽奖、发放奖品和奖品领完
4.活动的是个状态转换关系图
基本介绍
1.状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同行为的问题,状态和行为是一一对应的,状态之间可以互相转换
2.当一个对象的内在状态改变时,允许其改变其行为,这个对象看起来像是改变了其类
状态模式的角色及职责
1.Context类为环境角色,用于维护State实例,这个实例定义当前状态
2.State是抽象状态角色,定义一个接口封装与Context的一个特定接口相关行为
3.ConcreteState具体的角色状态,每个子类实现一个与Context的一个状态相关行为
public interface State{
void deduceMoney();
boolean raffle();
void dispensePrize();
}
@AllArgsConstructor
public class NoRaffleState implements State{
RaffleActivity actvivity;
@Override
public void deductMoney(){
System.out.println("扣除50积分成功,您可以抽奖了");
activity.setState(activity.getCanRaffleState());
}
@Override
public boolean raffle(){
System.out.println("扣了积分才能抽奖喔!");
return false;
}
@Override
public void dispensePrize(){
System.out.println("先抽奖啊混蛋!");
}
}
@AllArgsConstructor
public class CanRaffleState implements State{
RaffleActivity actvivity;
@Override
public void deductMoney(){
System.out.println("已经扣取过积分了");
}
@Override
public boolean raffle(){
System.out.println("正在抽奖请稍等");
Random r = new Random();
int num = r.nextOmt(10);
if(num == 0){
activity.setState(activity.getDispenseState);
return true;
}else{
System.out.println("没中哦");
activity.setState(activity.getNoRaffleState);
return false;
}
}
@Override
public void dispensePrize(){
System.out.println("先抽奖啊混蛋!");
}
}
@AllArgsConstructor
public class DispensePrizeState implements State{
RaffleActivity actvivity;
@Override
public void deductMoney(){
System.out.println("已经扣取过积分了");
}
@Override
public boolean raffle(){
System.out.println("无法抽奖");
}
@Override
public void dispensePrize(){
if(activity.getCount > 0){
System.out.println("恭喜中奖了");
activity.setState(activity.getNoRaffleState());
}else{
System.out.println("很遗憾,奖品发送完了");
activity.setState(activity.getDispenseOutState());
}
}
}
@AllArgsConstructor
public class DispenseOutState implements State{
RaffleActivity actvivity;
@Override
public void deductMoney(){
System.out.println("活动结束,下次早点来");
}
@Override
public boolean raffle(){
System.out.println("活动结束,下次早点来");
return false;
}
@Override
public void dispensePrize(){
System.out.println("活动结束,下次早点来");
}
}
@Data
public class RaffleActivity{
State state = null;
int count = 0;
State noRaffleState = new NoRaffleState(this);
State canRaffleState = new CanRaffleState(this);
State dispensePrizeState = new DispensePrizeState(this);
State dispenseOutState = new DispenseOutState(this);
public RaffleActivity(int count){
this.state = getNoRaffleState();
this.count = count;
}
public void debuctMoney(){
state.deductMoney();
}
public void raffle(){
if(state.raffle()){
state.dispensePrize();
}
}
public int getCount(){
int curCount = count;
count--;
return curCount;
}
}
public class Client{
public static void main(String[] args){
RaffleActivity activiy = new RaffleActivity(1);
for(int i = 0; i < 3; i++){
System.out.printle("第" + (i + 1) + "次抽奖");
activity.debuctMoney();
activity.raffle();
}
}
}
状态模式在实际项目-借贷平台源码剖析
1.借贷平台的订单,有审核-发布-抢单等等步骤,随着操作的不同,会改变订单的状态,项目中这个模块实现就会使用到状态模式
2.通常通过if/else判断订单的状态,从而实现不同的逻辑,伪代码如下
if(审核){
//审核逻辑
}else if(发布){
//发布逻辑
}else if(接单){
//接单逻辑
}
问题分析:这类代码难以应对变化,再添加一种状态时,我们需要手动添加if/else,在添加一种功能是,要对所有的状态进行判断,因此代码会变得越来越臃肿,并且一旦没有处理某个状态,便会发生极其严重的BUG,难以维护
3.使用状态模式完成借贷平台项目的审核模块[设计+代码]
借贷平台代码太多了,这里偷懒省略了,主要设计是使用接口和抽象类默认实现的方法实现了多种状态之间的互相关联和调用
状态模式的注意事项和细节
1.代码有很强的可读性,状态模式将每个状态的行为封装到一个类中
2.方便维护,将容易产生问题的if-else语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多if-else语句,而且很容易出错
3.符合开闭原则,容易增删状态
4.会产生很多类,每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度
5.当一个事件或者对象有很多状态,状态之间会相互转换,对不同的状态要求有不同的行为时,可以考虑使用状态模式