App抽奖活动问题
请编写程序完成app抽奖活动,要求如下:
- 加入每参加一次活动需要扣除用户50积分,中奖概率是10%。
- 奖品数量固定,抽完就不能再抽奖。
- 活动有4个状态:可以抽奖、不能抽奖、发放奖品和奖品领完。
- 活动的状态关系图如图:
状态模式的介绍
- 状态模式(State pattern):它主要用来解决对象在不同状态之间转换时,需要对外输出不同行为的问题。状态和行为是一一对应的,状态之间可以相互转换。
- 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来是改变了其类。
类图
类图说明(即状态模式的角色和职责)
- Context为环境角色,用于维护State实例,这个实例定义当前状态。
- State是抽象状态角色,定义一个接口封装与Context的一个特点接口相关行为。
- ConcreteState具体的状态角色,每个子类实现一个与Context相关的一个状态的行为。
状态模式实现APP抽奖活动
相关代码:
public abstract class State {
private RaffleActivity raffleActivity;
public State(RaffleActivity raffleActivity) {
this.raffleActivity = raffleActivity;
}
public RaffleActivity getRaffleActivity() {
return raffleActivity;
}
/**
* 扣减积分
*/
public abstract void deductMoney();
/**
* 抽奖
*/
public abstract void raffle();
/**
* 发放奖品
*/
public abstract void dispensePrize();
}
/**
* 不能抽奖的状态
**/
public class NoRaffleState extends State {
public NoRaffleState(RaffleActivity raffleActivity) {
super(raffleActivity);
}
@Override
public void deductMoney() {
System.out.println("扣除50积分成功,可以抽奖了");
getRaffleActivity().setState(getRaffleActivity().getCanRaffleState());
}
@Override
public boolean raffle() {
System.out.println("扣了积分才能抽奖");
return false;
}
@Override
public void dispensePrize() {
System.out.println("不能发放奖品");
}
}
/**
* 可以抽奖的状态
**/
public class CanRaffleState extends State {
public CanRaffleState(RaffleActivity raffleActivity) {
super(raffleActivity);
}
@Override
public void deductMoney() {
System.out.println("已经扣过积分了,请抽奖");
}
@Override
public boolean raffle() {
Random random = new Random();
int randNum = random.nextInt(10);
if (randNum == 0) {
getRaffleActivity().setState(getRaffleActivity().getDispenseState());
return true;
} else {
System.out.println("很遗憾,没有抽中奖品,谢谢参与!");
getRaffleActivity().setState(getRaffleActivity().getNoRaffleState());
return false;
}
}
@Override
public void dispensePrize() {
System.out.println("不能发放奖品");
}
}
/**
* 发放奖品的状态
**/
public class DispenseState extends State {
public DispenseState(RaffleActivity raffleActivity) {
super(raffleActivity);
}
@Override
public void deductMoney() {
System.out.println("已经扣过积分了");
}
@Override
public boolean raffle() {
System.out.println("已经抽过奖了");
return false;
}
@Override
public void dispensePrize() {
if (getRaffleActivity().getCount() > 0) {
System.out.println("恭喜中奖了");
int count = getRaffleActivity().getCount() - 1;
getRaffleActivity().setCount(count);
if (count > 0) {
getRaffleActivity().setState(getRaffleActivity().getNoRaffleState());
} else {
getRaffleActivity().setState(getRaffleActivity().getDispenseOutState());
}
} else {
System.out.println("很遗憾,奖品领完了");
getRaffleActivity().setState(getRaffleActivity().getDispenseOutState());
}
}
}
/**
* 奖品发放完的状态
**/
public class DispenseOutState extends State {
public DispenseOutState(RaffleActivity raffleActivity) {
super(raffleActivity);
}
@Override
public void deductMoney() {
System.out.println("活动结束");
}
@Override
public boolean raffle() {
System.out.println("活动结束");
return false;
}
@Override
public void dispensePrize() {
System.out.println("活动结束");
}
}
状态模式的注意事项及细节
- 代码有很强的可读性。状态模式将每个状态的很为封装到对应的一个类中
- 方便维护,将容易产生问题的if/else语句删除了,如果每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产生出很多if-else语句,而且很容易出错。
- 符合ocp原则。容易增删状态
- 会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度。
- 应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式。