介绍

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

原理

image-20201016235321857.png
对原理类图的说明-即(状态模式的角色及职责)

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

案例

请编写程序完成APP抽奖活动 具体要求如下:

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

image-20201016235456558.pngimage-20201016235609024.png

  1. //state抽象类
  2. public abstract class State {
  3. public abstract void deductMoney(); //抽奖前扣除积分
  4. public abstract boolean raffle(); //抽奖
  5. public abstract void dispensePrize();//发奖
  6. }
  7. //未抽奖状态
  8. public class NoRaffleState extends State{
  9. private int integral; //抽奖积分
  10. private Activity activity;
  11. public NoRaffleState(int integral, Activity activity) {
  12. this.integral = integral;
  13. this.activity = activity;
  14. }
  15. @Override
  16. public void deductMoney() {
  17. if (this.integral>50){
  18. this.integral=this.integral-50;
  19. activity.setState(activity.getCanRaffleState());
  20. System.out.println("50积分已扣除");
  21. }
  22. else {
  23. System.out.println("很抱歉积分不足,不能抽奖");
  24. }
  25. }
  26. @Override
  27. public boolean raffle() {
  28. System.out.println("很抱歉,不能抽奖");
  29. return false;
  30. }
  31. @Override
  32. public void dispensePrize() {
  33. System.out.println("很抱歉,不能发放奖品");
  34. }
  35. }
  36. //可以抽奖状态
  37. public class CanRaffleState extends State{
  38. private Activity activity;
  39. public CanRaffleState(Activity activity) {
  40. this.activity = activity;
  41. }
  42. @Override
  43. public void deductMoney() {
  44. System.out.println("很抱歉,不能扣积分");
  45. }
  46. @Override
  47. public boolean raffle() {
  48. System.out.println("开始抽奖----");
  49. Random random = new Random();
  50. int num = random.nextInt(10); //随机在1-10之前产生随机数
  51. if (num==0){
  52. activity.setState(activity.getDispenseState());
  53. return true;
  54. }else {
  55. System.out.println("很遗憾,没有中奖");
  56. activity.setState(activity.getNoRaffleState());
  57. return false;
  58. }
  59. }
  60. @Override
  61. public void dispensePrize() {
  62. System.out.println("很抱歉,不能发奖");
  63. }
  64. }
  65. //发奖状态
  66. public class DispenseState extends State{
  67. private Activity activity;
  68. public DispenseState(Activity activity) {
  69. this.activity = activity;
  70. }
  71. @Override
  72. public void deductMoney() {
  73. System.out.println("很抱歉,不能扣除积分");
  74. }
  75. @Override
  76. public boolean raffle() {
  77. System.out.println("很抱歉,不能抽奖");
  78. return false;
  79. }
  80. @Override
  81. public void dispensePrize() {
  82. if (activity.getPrizeCount()>0){
  83. activity.setState(activity.getNoRaffleState());//领奖后会到未抽奖状态
  84. System.out.println("恭喜你,请领取你的奖品");
  85. }
  86. }
  87. }
  1. //抽奖活动类
  2. public class Activity {
  3. private State state; //初始状态为空
  4. int PrizeCount; //奖品数量
  5. private NoRaffleState noRaffleState = new NoRaffleState(50*1000,this);
  6. private CanRaffleState canRaffleState = new CanRaffleState(this);
  7. private DispenseState dispenseState =new DispenseState(this);
  8. public Activity(int prizeCount) {
  9. this.state = noRaffleState; //构建Activity对象时初始化状态为未抽奖状态
  10. this.PrizeCount = prizeCount;
  11. }
  12. public void debuctMoney(){
  13. if (PrizeCount==0){ //判断奖品是否还有,没有则活动结束
  14. System.out.println("奖品已发送完毕,抽奖活动结束");
  15. System.exit(0);
  16. }
  17. state.deductMoney();
  18. }
  19. public void raffle(){ //抽奖
  20. if(state.raffle()){ //如果中奖则发奖
  21. state.dispensePrize();
  22. }
  23. }
  24. public State getState() {
  25. return state;
  26. }
  27. public void setState(State state) {
  28. this.state = state;
  29. }
  30. public int getPrizeCount() { //每次领完奖后奖品-1
  31. int Count = PrizeCount;
  32. PrizeCount--;
  33. return Count;
  34. }
  35. public void setPrizeCount(int prizeCount) {
  36. PrizeCount = prizeCount;
  37. }
  38. public NoRaffleState getNoRaffleState() {
  39. return noRaffleState;
  40. }
  41. public void setNoRaffleState(NoRaffleState noRaffleState) {
  42. this.noRaffleState = noRaffleState;
  43. }
  44. public CanRaffleState getCanRaffleState() {
  45. return canRaffleState;
  46. }
  47. public void setCanRaffleState(CanRaffleState canRaffleState) {
  48. this.canRaffleState = canRaffleState;
  49. }
  50. public DispenseState getDispenseState() {
  51. return dispenseState;
  52. }
  53. public void setDispenseState(DispenseState dispenseState) {
  54. this.dispenseState = dispenseState;
  55. }
  56. }
  1. //测试
  2. public class Client {
  3. public static void main(String[] args) {
  4. Activity activity = new Activity(2);
  5. for (int i = 0; i < 100; i++) { //模拟100次抽奖
  6. System.out.println("------第"+(i+1)+"次抽奖------");
  7. activity.debuctMoney();
  8. activity.raffle();
  9. }
  10. }
  11. }

image-20201017000659379.png

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

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

态要求有不同的行为的时候,可以考虑使用状态模式