状态设计模式解读

简介: 状态设计模式解读

734cae67d8164fa7b5c2cad65c347c23.png

问题引进

请编写程序完成 APP 抽奖活动 具体要求如下:
1) 假如每参加一次这个活动要扣除用户 50 积分,中奖概率是 10%
2) 奖品数量固定,抽完就不能抽奖
3) 活动有四个状态: 可以抽奖、不能抽奖、发放奖品和奖品领完
4) 活动的四个状态转换关系图(下图)

状态模式基本介绍

基本介绍

1) 状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换
2) 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了

状态模式的原理类图

对原理类图的说明

1) Context 类为环境角色, 用于维护 State 实例,这个实例定义当前状态
2) State 是抽象状态角色,定义一个接口封装与 Context 的一个特点接口相关行为
3) ConcreteState 具体的状态角色,每个子类实现一个与 Context 的一个状态相关行为

状态模式解决 APP 抽奖问题

1) 应用实例要求

完成 APP 抽奖活动项目,使用状态模式.

2) 思路分析和图解(类图)

-定义出一个接口叫状态接口,每个状态都实现它。
-接口有扣除积分方法、抽奖方法、发放奖品方法

代码落地

State

1. public abstract class State {
2. 
3. //扣除积分
4. public abstract  void deductMoney();
5. 
6. //是否抽中奖品
7. public abstract  boolean raffle();
8. 
9. //发放奖品
10. public abstract  void dispensePrize();
11. 
12. }

NoRaffleState

1. public class NoRaffleState extends  State{
2. 
3.     RaffleActivity activity;
4. 
5. public NoRaffleState(RaffleActivity activity) {
6. this.activity = activity;
7.     }
8. 
9. @Override
10. public void deductMoney() {
11.         System.out.println("扣除 50 积分成功,您可以抽奖了");
12.         activity.setState(activity.getCanRaffleState());
13.     }
14. 
15. @Override
16. public boolean raffle() {
17.         System.out.println("扣了积分才能抽奖喔!");
18. return false;
19.     }
20. 
21. @Override
22. public void dispensePrize() {
23.         System.out.println("不能发放奖品");
24.     }
25. }

CanRaffleState  

1. //不能抽奖状态
2. public class CanRaffleState extends  State{
3. 
4.     RaffleActivity activity;
5. 
6. public CanRaffleState(RaffleActivity activity) {
7. this.activity = activity;
8.     }
9. 
10. //已经扣除了积分,不能再扣
11. @Override
12. public void deductMoney() {
13.         System.out.println("引进扣除过积分,不用进行积分扣除");
14.     }
15. 
16. 
17. //可以抽奖, 抽完奖后,根据实际情况,改成新的状态
18. @Override
19. public boolean raffle() {
20.         System.out.println("正在抽奖,请稍等!");
21. Random r = new Random();
22. int num = r.nextInt(10);
23. // 10%中奖机会
24. if(num == 0){
25. // 改变活动状态为发放奖品 context
26.             activity.setState(activity.getDispenseState());
27. return true;
28.         }else{
29.             System.out.println("很遗憾没有抽中奖品!");
30. // 改变状态为不能抽奖
31.             activity.setState(activity.getNoRafflleState());
32. return false;
33.         }
34.     }
35. 
36. @Override
37. public void dispensePrize() {
38.         System.out.println("没中奖,不能发放奖品");
39.     }
40. }

DispenseState  

1. /**
2.  * 发放奖品状态
3.  */
4. public class DispenseState extends State  {
5. 
6. // 初始化时传入活动引用,发放奖品后改变其状态
7.     RaffleActivity activity;
8. 
9. public DispenseState(RaffleActivity activity) {
10. this.activity = activity;
11.     }
12. 
13. @Override
14. public void deductMoney() {
15.         System.out.println("不能扣除积分");
16.     }
17. 
18. @Override
19. public boolean raffle() {
20.         System.out.println("不能抽奖");
21. return false;
22.     }
23. 
24. @Override
25. public void dispensePrize() {
26. if(activity.getCount() > 0){
27.             System.out.println("恭喜中奖了");
28. // 改变状态为不能抽奖
29.             activity.setState(activity.getNoRafflleState());
30.         }else{
31.             System.out.println("很遗憾,奖品发送完了");
32. // 改变状态为奖品发送完毕, 后面我们就不可以抽奖
33.             activity.setState(activity.getDispensOutState());
34. //System.out.println("抽奖活动结束");
35.         }
36.     }
37. }

DispenseOutState  

1. /**
2.  * 不能抽奖状态
3.  */
4. public class DispenseOutState extends  State{
5. 
6. // 初始化时传入活动引用
7.     RaffleActivity activity;
8. 
9. public DispenseOutState(RaffleActivity activity) {
10. this.activity = activity;
11.     }
12. 
13. @Override
14. public void deductMoney() {
15.         System.out.println("奖品发送完了,请下次再抽奖");
16.     }
17. 
18. @Override
19. public boolean raffle() {
20.         System.out.println("奖品发送完了,请下次再抽奖");
21. return false;
22.     }
23. 
24. @Override
25. public void dispensePrize() {
26.         System.out.println("奖品发送完了,请下次再参加");
27.     }
28. }

RaffleActivity  

1. public class RaffleActivity {
2. //state表示活动当前的状态,是变化
3.     State state=null;
4. //奖品数量
5. int count=0;
6. //四个属性,表示四种状态
7.     State noRafflleState=new NoRaffleState(this);
8.     State canRaffleState=new CanRaffleState(this);
9.     State dispensOutState=new DispenseOutState(this);
10.     State dispenseState= new DispenseState(this);
11. //构造器
12. //1. 初始化当前的状态为 noRafflleState(即不能抽奖的状态)
13. //2. 初始化奖品的数量
14. public RaffleActivity( int count) {
15. this.state = getNoRafflleState();
16. this.count = count;
17.     }
18. //扣分, 调用当前状态的 deductMoney
19. public void debuctMoney(){
20.         state.deductMoney();
21.     }
22. //抽奖
23. public void raffle() {
24. // 如果当前的状态是抽奖成功
25. if(state.raffle()){
26. //领取奖品
27.             state.dispensePrize();
28.         }
29.     }
30. public State getState() {
31. return state;
32.     }
33. public void setState(State state) {
34. this.state = state;
35.     }
36. //这里请大家注意,每领取一次奖品,count--
37. public int getCount() {
38. int curCount = count;
39.         count--;
40. return curCount;
41.     }
42. public void setCount(int count) {
43. this.count = count;
44.     }
45. 
46. public State getNoRafflleState() {
47. return noRafflleState;
48.     }
49. public void setNoRafflleState(State noRafflleState) {
50. this.noRafflleState = noRafflleState;
51.     }
52. public State getCanRaffleState() {
53. return canRaffleState;
54.     }
55. public void setCanRaffleState(State canRaffleState) {
56. this.canRaffleState = canRaffleState;
57.     }
58. public State getDispenseState() {
59. return dispenseState;
60.     }
61. public void setDispenseState(State dispenseState) {
62. this.dispenseState = dispenseState;
63.     }
64. public State getDispensOutState() {
65. return dispensOutState;
66.     }
67. 
68. public void setDispensOutState(State dispensOutState) {
69. this.dispensOutState = dispensOutState;
70.     }
71. }

ClientTest  

1. public class ClientTest {
2. public static void main(String[] args) {
3. // 创建活动对象,奖品有 1 个奖品
4. RaffleActivity activity = new RaffleActivity(1);
5. // 我们连续抽 300 次奖
6. for (int i = 0; i < 30; i++) {
7.             System.out.println("--------第" + (i + 1) + "次抽奖----------");
8. // 参加抽奖,第一步点击扣除积分
9.             activity.debuctMoney();
10. // 第二步抽奖
11.             activity.raffle();
12.         }
13.     }
14. }

--------第1次抽奖----------

扣除 50 积分成功,您可以抽奖了

正在抽奖,请稍等!

很遗憾没有抽中奖品!

--------第2次抽奖----------

扣除 50 积分成功,您可以抽奖了

正在抽奖,请稍等!

很遗憾没有抽中奖品!

--------第3次抽奖----------

扣除 50 积分成功,您可以抽奖了

正在抽奖,请稍等!

很遗憾没有抽中奖品!

--------第4次抽奖----------

扣除 50 积分成功,您可以抽奖了

正在抽奖,请稍等!

很遗憾没有抽中奖品!

--------第5次抽奖----------

扣除 50 积分成功,您可以抽奖了

正在抽奖,请稍等!

很遗憾没有抽中奖品!

--------第6次抽奖----------

扣除 50 积分成功,您可以抽奖了

正在抽奖,请稍等!

恭喜中奖了

--------第7次抽奖----------

扣除 50 积分成功,您可以抽奖了

正在抽奖,请稍等!

很遗憾,奖品发送完了

--------第8次抽奖----------

奖品发送完了,请下次再抽奖

奖品发送完了,请下次再抽奖

状态模式的注意事项和细节

1) 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中
2) 方便维护。将容易产生问题的 if-else 语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多 if-else 语句,而且容易出错
3) 符合“开闭原则”。容易增删状态
4) 会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度
5) 应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式

相关文章
|
设计模式 算法 Java
劳动节期间学习设计模式-模板方法模式
劳动节期间学习设计模式-模板方法模式
|
8月前
|
设计模式 算法 C++
从 C++ 优化状态机实现:结合设计模式的实用指南
从 C++ 优化状态机实现:结合设计模式的实用指南
592 1
|
设计模式 前端开发 数据安全/隐私保护
前端实现设计模式之状态模式
状态模式是一种行为型设计模式,用于在对象内部状态发生变化时改变其行为。状态模式将对象的行为封装在不同的状态类中,使得对象在不同的状态下可以有不同的行为。在前端开发中,状态模式常用于管理组件的状态和行为,以实现复杂的交互逻辑。本文将介绍状态模式的概念和应用,并提供具体的代码示例和解读。
171 0
|
8月前
|
设计模式
状态模式--设计模式
状态模式--设计模式
47 0
|
8月前
|
设计模式 存储 前端开发
【设计模式】之调停者模式
调停者模式是一种有助于降低对象之间耦合度的设计模式。它通过引入一个调停者对象来集中处理一组对象之间的交互,使得代码更易于维护和扩展。在前端开发中,调停者模式可以应用于表单验证、消息订阅与发布、组件间通信等场景。尽管调停者模式可能会增加系统的复杂性,并且调停者对象可能变得庞大和复杂,但它仍然是一种有价值的设计模式,可以提高代码的可读性和可维护性。
76 0
【设计模式】之调停者模式
|
8月前
|
设计模式 算法 调度
行为型设计模式:模板设计模式/观察者设计模式/策略设计模式/责任链设计模式
行为型设计模式:模板设计模式/观察者设计模式/策略设计模式/责任链设计模式
66 0
|
8月前
|
设计模式
二十三种设计模式-解密状态模式:优雅地管理对象状态
二十三种设计模式-解密状态模式:优雅地管理对象状态
109 0
|
8月前
|
设计模式 监控 容器
设计模式-观察者模式(观察者模式的需求衍变过程详解,关于监听的理解)
设计模式-观察者模式(观察者模式的需求衍变过程详解,关于监听的理解)
|
设计模式 Java 编译器
设计模式学习(五):State状态模式
在面向对象编程中,是用类表示对象的。也就是说,程序的设计者需要考虑用类来表示什么东西。类对应的东西可能存在于真实世界中,也可能不存在于真实世界中。
167 0
设计模式学习(五):State状态模式