不要羡慕别人的成功,那是牺牲了安逸换来的;不要羡慕别人的才华,那是私底下的努力换来的;不要羡慕别人的成熟,那是经历与沧桑换来的。可以欣赏,但不要嫉妒,因为那都是别人应该得到的。
设计模式学习,近期我会把23种设计模式都写成博客,敬请期待~
—2021/1/26
定义
状态模式允许一个对象在其状态改变时,改变它的行为,对象看起来似乎修改了它的类。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
项目需求
图片理解(1.1)
:
图画的有点点点丑,不喜勿喷o(╥﹏╥)o
分析:
这是一个抽奖的活动,每抽一次奖品扣除10积分
- 有积分:开始抽奖
- 没有积分:结束程序
如果中奖:
- 发送奖品
- 中奖,但是奖品已经全部发完,结束程序
角色分析
-
环境角色(StateActivity):定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
-
抽象状态角色(State):定义一个接口,用以封装环境(StateActivity)对象的一个特定的状态所对应的行为。
-
具体状态角色(State的实现类):每一个具体状态类都实现了环境(StateActivity)的一个状态所对应的行为。
代码实现
抽象状态角色(State):
public interface State {
/**
* 扣除10积分抽奖
*/
public void deduceMoney();
/**
*抽奖
* @return true 抽中
*/
public boolean raffle();
/**
* 发奖品
*/
public void dispensePrize();
}
StateActivity(状态活动类,包含所有 的状态)
public class StateActivity {
//不能抽奖
private final State noRaffleState;
//可以抽奖
private final State canRaffleState;
//中奖
private final State dispenseState;
//已中奖 奖品已发完
private final State dispenseOutState;
//当前状态
public State state = null;
//奖品数量
public int number;
//积分
public int integral;
/**
* @param number 奖品数量
*/
public StateActivity(int number, int integral) {
noRaffleState = new NoRaffleState(this);
canRaffleState = new CanRaffleState(this);
dispenseState = new DispenseState(this);
dispenseOutState = new DispenseOutState(this);
this.number = number;
this.integral = integral;
//默认为不能抽奖
state = getNoRaffleState();
}
/**
* 开始抽奖
*/
public void startLottery() {
state.deduceMoney();
//判断奖品是否抽中 奖品抽中
if (state.raffle()) {
//发放奖品
state.dispensePrize();
}
}
getter... setter...
}
StateActivity参数介绍:
- int number; //奖品数量
- public int integral; //积分
NoRaffleState(扣除积分,开始抽奖,积分不足无法抽奖)
public class NoRaffleState implements State {
private StateActivity activity;
public NoRaffleState(StateActivity activity) {
this.activity = activity;
}
//扣除积分
@Override
public void deduceMoney() {
//积分>10才可以抽奖
Log.i("状态模式", "当前积分为:"+activity.integral );
if (activity.integral >= 10) {
//每抽一次奖 扣10积分
activity.integral -= 10;
Log.i("状态模式", "已扣除积分,可以抽奖");
//扣除了积分 将状态修改为开始抽奖模式
activity.setState(activity.getCanRaffleState());
}else{
Log.i("状态模式", "积分不足");
}
}
//抽奖
@Override
public boolean raffle() {
Log.i("状态模式", "扣除积分在抽奖哦!");
return false;
}
//发送奖品(当前是扣积分状态,不能发送奖品)
@Override
public void dispensePrize() {
Log.i("状态模式", "无法发送奖品");
}
}
CanRaffleState(开始抽奖,使用随机数.抽奖几率为10/1)
public class CanRaffleState implements State{
private StateActivity activity;
private Random random;
public CanRaffleState(StateActivity activity) {
this.activity = activity;
}
@Override//扣积分(当前是抽奖状态,不能扣积分)
public void deduceMoney() {
Log.i("状态模式","开始抽奖~");
activity.setState(this);
}
/**
*
* @return true抽中
*/
@Override
public boolean raffle() {
//使用随机数 10/1 的几率中奖
random = new Random();
int anInt = random.nextInt(10);
if (anInt == 0) {
Log.i("状态模式","恭喜您抽中了~");
//中奖 将状态改为发送奖品
activity.setState(activity.getDispenseState());
return true;
} else{
Log.i("状态模式","很遗憾,没有中奖~");
//为中奖 将状态改为扣除积分来抽奖
activity.setState(activity.getNoRaffleState());
return false;
}
}
@Override//发送奖品(当前是抽奖状态,不能发送奖品)
public void dispensePrize() {
Log.i("状态模式","不能发放奖品");
}
}
DispenseState (抽中奖品状态:)
public class DispenseState implements State {
private StateActivity activity;
public DispenseState(StateActivity activity) {
this.activity = activity;
}
@Override//当前是抽中奖状态 不能扣积分
public void deduceMoney() {
Log.i("状态模式", "正在发放奖品,不能扣积分~");
}
@Override//当前是抽中奖状态,不能抽奖
public boolean raffle() {
Log.i("状态模式", "正在发放奖品,不能抽奖~");
return false;
}
@Override//当前是抽中奖状态 查看奖品个数发送奖品
public void dispensePrize() {
int number = activity.getNumber();
Log.i("状态模式", "当前奖品个数为:" + number);
//奖品总数>0说明有奖品
if (number > 0) {
//领取奖品后让奖品数量-1
activity.number--;
Log.i("状态模式", "奖品已经发放~");
//发放完奖品后将状态改为不能发放奖品
activity.setState(activity.getNoRaffleState());
} else {
Log.i("状态模式", "很遗憾,您中奖了,可是奖品发送完了~");
activity.setState(activity.getDispenseOutState());
}
}
}
DispenseOutState (抽中奖,但是奖品已经全部发完)
public class DispenseOutState implements State {
private StateActivity activity;
public DispenseOutState(StateActivity activity) {
this.activity = activity;
}
@Override//当前是奖品发完状态 不能扣积分
public void deduceMoney() {
Log.i("状态模式", "奖品已经全部发完");
}
@Override//当前是奖品发完状态 不能抽奖
public boolean raffle() {
Log.i("状态模式", "奖品已经全部发完");
return false;
}
@Override//当前是奖品发完状态 奖品发送完毕
public void dispensePrize() {
Log.i("状态模式", "奖品已经全部发完");
}
}
测试类(客户端):
StateActivity stateActivity = new StateActivity(2,300);
for (int i = 0; i < 30; i++) {
Log.i("状态模式"," ==========+第"+(i+1)+"次抽奖================");
//开始抽奖
stateActivity.startLottery();
}
StateActivity参数介绍:
- 参数一:有2个奖品
- 参数二:有300积分(没抽一次奖扣除10积分)
测试结果:
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第1次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:300
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第2次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:290
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第3次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:280
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第4次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:270
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第5次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:260
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第6次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:250
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第7次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:240
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第8次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:230
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第9次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:220
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第10次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:210
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第11次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:200
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 恭喜您抽中了~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前奖品个数为:2
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经发放~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第12次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:190
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第13次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:180
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第14次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:170
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第15次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:160
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第16次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:150
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第17次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:140
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 恭喜您抽中了~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前奖品个数为:1
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经发放~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第18次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:130
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第19次抽奖================
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:120
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.560 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第20次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:110
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第21次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:100
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第22次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:90
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第23次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:80
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,没有中奖~
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第24次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前积分为:70
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 已扣除积分,可以抽奖
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 恭喜您抽中了~
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 当前奖品个数为:0
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 很遗憾,您中奖了,可是奖品发送完了~
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第25次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第26次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第27次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第28次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第29次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: ==========+第30次抽奖================
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
2021-01-26 16:32:15.561 32602-32602/demo.ht.com.design_pattern I/状态模式: 奖品已经全部发完
分析:
第11次抽中奖,当前奖品个数还有2个(发送1个奖品还剩1个奖品)
第17次抽中奖,当前奖品个数还有1个(发送1个奖品还剩0个奖品)
第24次抽中奖,当前奖品个数还有0个,没有奖品可发送!
总结:
优点:
-
结构清晰,避免了过多的switch…case或if…else语句的使用
-
很好的体现了开闭原则和单一职责原则,想要增加状态就增加子类,想要修改状态就修改子类即可
-
封装性非常好,状态变化放置到了类的内部来实现,外部调用不需要知道类内部如何实现状态和行为的变换
缺点:
- 子类会太多,也即类膨胀
- 耦合性有点高,因为吧所有的状态都交给了状态活动类(StateActivity)
原创不易,您的点赞就是对我最大的支持~