状态设计模式解读

简介: 状态设计模式解读

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) 应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式

相关文章
|
JSON 网络协议 数据格式
Docker(35)- docker inspect 命令详解
Docker(35)- docker inspect 命令详解
960 0
Docker(35)- docker inspect 命令详解
|
机器学习/深度学习 搜索推荐 算法
Learning Disentangled Representations for Recommendation | NIPS 2019 论文解读
近年来随着深度学习的发展,推荐系统大量使用用户行为数据来构建用户/商品表征,并以此来构建召回、排序、重排等推荐系统中的标准模块。普通算法得到的用户商品表征本身,并不具备可解释性,而往往只能提供用户-商品之间的attention分作为商品粒度的用户兴趣。我们在这篇文章中,想仅通过用户行为,学习到本身就具备一定可解释性的解离化的用户商品表征,并试图利用这样的商品表征完成单语义可控的推荐任务。
24080 0
Learning Disentangled Representations for Recommendation | NIPS 2019 论文解读
|
12月前
|
Web App开发 JavaScript Java
自动化测试的利剑:Selenium WebDriver入门与实践
【9月更文挑战第21天】在软件开发的海洋中,自动化测试犹如一艘船,帮助开发者们快速航行至质量保证的彼岸。本文将作为你的罗盘,指引你了解和掌握Selenium WebDriver这一强大的自动化测试工具。通过深入浅出的方式,我们将探索Selenium WebDriver的基本概念、安装过程以及编写简单测试脚本的方法。无论你是刚接触自动化测试的新手,还是希望提升测试技能的开发者,这篇文章都将为你提供有价值的指导。
|
监控 关系型数据库 数据库
关系型数据库考虑索引的选择性
【5月更文挑战第20天】
242 4
|
人工智能 安全 API
警觉!AI工具可能正在泄露您的数据...
不论是企业自身使用大模型训练自己的AI服务,还是内部员工使用AI工具提高生产力,当下都已逐渐演变为常态。近期,国内某互联网大厂也被传出正通过API将ChatGPT集成至内部的应用程序和服务中用以打造自己的大模型....然而,潮流的背后,潜在的安全隐患是否能够被及时识别呢?...
|
安全 Shell 网络安全
Git学习---Git快速入门、Git基础使用、Git进阶使用、Git服务器使用(IDEA集成GitHub、Gitee、GitLab)、GitHub Desktop客户端
Git学习---Git快速入门、Git基础使用、Git进阶使用、Git服务器使用(IDEA集成GitHub、Gitee、GitLab)、GitHub Desktop客户端
336 0
|
机器学习/深度学习 PyTorch API
PyTorch-PaddlePaddle模型转化&API映射关系对照表
PyTorch-PaddlePaddle模型转化&API映射关系对照表
601 0
PyTorch-PaddlePaddle模型转化&API映射关系对照表
|
人工智能 数据可视化 物联网
欧阳日辉:元宇宙技术创新与未来金融的遐想
元宇宙本身并不是用来替代现实的,也不是用来逃避现实的,而是用来超越现实的。我思考的问题是:元宇宙的经济体系是什么?元宇宙世界的金融是什么?元宇宙对金融发展有哪些影响?我们如何利用元宇宙技术创新金融发展?
欧阳日辉:元宇宙技术创新与未来金融的遐想
|
机器学习/深度学习 算法 数据中心
05_特征工程—降维
05_特征工程—降维
314 0
05_特征工程—降维
|
数据库 数据安全/隐私保护 Shell
借助URLOS快速安装Apache-PHP-5.6网站环境
环境需求 最低硬件配置:1核CPU,1G内存(1+1)提示:如果你的应用较多,而主机节点的硬件配置较低,建议在部署节点时开通虚拟虚拟内存; 生产环境建议使用2G或以上内存; 推荐安装系统:Ubuntu-16.
1004 3