一、状态模式基本介绍
1、基本介绍
(1)状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换;
(2)当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类;
2、状态模式的原理类图
对原理类图的说明——即(状态模式的角色及职责)
(1)Context 类为环境角色,用于维护 State 实例,这个实例定义当前状态;
(2)State 是抽象状态角色,定义一个接口封装与 Context 的一个特点接口相关行为;
(3)ConcreteState 具体的状态角色,每个子类实现一个与 Context 的一个状态相关行为;
二、状态模式解决 APP抽奖问题
1、应用实例要求
完成 APP 抽奖活动项目,使用状态模式
2、思路分析和图解
定义出一个接口叫状态接口,每个状态都实现它。
接口有扣除积分方法、抽奖方法、发放奖品方法。
3、代码实现
状态接口类:
1 /**
2 * 状态 接口
3 */
4 public interface State {
5
6 /**
7 * 扣除积分 - 50
8 */
9 public void deductMoney();
10
11 /**
12 * 是否抽中奖品
13 * @return
14 */
15 public boolean raffle();
16
17
18 /**
19 * 发放奖品
20 */
21 public void dispensePrize();
22 }
各个状态实现类:
1 /**
2 * 不能抽奖状态
3 */
4 public class NoRaffleState implements State{
5
6 /**
7 * 初始化时传入活动引用,扣除积分后改变其状态
8 */
9 RaffleActivity activity;
10
11 public NoRaffleState(RaffleActivity activity) {
12 this.activity = activity;
13 }
14
15 /**
16 * 当前状态可以扣积分,扣除后,将状态设置成可以抽奖状态
17 */
18 @Override
19 public void deductMoney() {
20 System.out.println("扣除50积分成功,您可以抽奖了");
21 activity.setState(activity.getCanRaffleState());
22 }
23
24 /**
25 * 抽奖,当前状态是不能抽奖的
26 * @return
27 */
28 @Override
29 public boolean raffle() {
30 System.out.println("扣了积分才能抽奖哦!");
31 return false;
32 }
33
34 @Override
35 public void dispensePrize() {
36 System.out.println("不能发放奖品");
37 }
38 }
39 ------------------------------------------------------
40 /**
41 * 可以抽奖的状态
42 */
43 public class CanRaffleState implements State{
44
45 /**
46 * 初始化时传入活动引用,扣除积分后改变其状态
47 */
48 RaffleActivity activity;
49
50 public CanRaffleState(RaffleActivity activity) {
51 this.activity = activity;
52 }
53
54 @Override
55 public void deductMoney() {
56 System.out.println("已经扣取过了积分");
57 }
58
59 /**
60 * 可以抽奖,抽完奖后,根据实际情况,设置新的状态
61 * @return
62 */
63 @Override
64 public boolean raffle() {
65 System.out.println("正在抽奖,请稍等!");
66 Random random = new Random();
67 int num = random.nextInt(10);
68 if (num == 0) {
69 //改变活动状态为发放奖品 context
70 activity.setState(activity.getDispenseState());
71 return true;
72 }else {
73 System.out.println("很遗憾没有抽中奖品!");
74 //改变状态为不能抽奖
75 activity.setState(activity.getNoRaffleState());
76 return false;
77 }
78 }
79
80 /**
81 * 不能发放奖品
82 */
83 @Override
84 public void dispensePrize() {
85 System.out.println("没有中奖,不能发放奖品");
86 }
87 }
88 ------------------------------------------------------
89 /**
90 * 发送奖品的状态
91 */
92 public class DispenseState implements State{
93
94 /**
95 * 初始化时传入活动引用,扣除积分后改变其状态
96 */
97 RaffleActivity activity;
98
99 public DispenseState(RaffleActivity activity) {
100 this.activity = activity;
101 }
102
103 /**
104 * 不能扣除积分
105 */
106 @Override
107 public void deductMoney() {
108 System.out.println("不能扣除积分");
109 }
110
111 /**
112 * 不能抽奖
113 * @return
114 */
115 @Override
116 public boolean raffle() {
117 System.out.println("不能抽奖");
118 return false;
119 }
120
121 /**
122 * 发放奖品
123 */
124 @Override
125 public void dispensePrize() {
126 if (activity.getCount() > 0) {
127 System.out.println("恭喜中奖了!");
128 // 改变状态为不能抽奖
129 activity.setState(activity.getNoRaffleState());
130 }else {
131 System.out.println("很遗憾,奖品发送完了");
132 //改变状态为奖品发送完毕,后面就不可以再抽奖了
133 activity.setState(activity.getDispenseOutState());
134 System.out.println("抽奖结束,多谢参与");
135 System.exit(0);
136 }
137 }
138 }
139 ------------------------------------------------------
140 /**
141 * 奖品发放完毕状态
142 * 说明:当我们 activity 改变成 DispenseOutState,抽奖活动结束了
143 */
144 public class DispenseOutState implements State{
145
146 /**
147 * 初始化时传入活动引用,扣除积分后改变其状态
148 */
149 RaffleActivity activity;
150
151 public DispenseOutState(RaffleActivity activity) {
152 this.activity = activity;
153 }
154
155 @Override
156 public void deductMoney() {
157 System.out.println("奖品发送完了,请下次再参加");
158 }
159
160 @Override
161 public boolean raffle() {
162 System.out.println("奖品发送完了,请下次再参加");
163 return false;
164 }
165
166 @Override
167 public void dispensePrize() {
168 System.out.println("奖品发送完了,请下次再参加");
169 }
170 }
Context 上下文对象:
1 /**
2 * 抽奖活动
3 */
4 public class RaffleActivity {
5
6 /**
7 * 表示当前的状态,是变化的
8 */
9 private State state = null;
10
11 /**
12 * 奖品数量
13 */
14 int count = 0;
15
16 /**
17 * 下面四个属性,表示四种状态
18 */
19 State noRaffleState = new NoRaffleState(this);
20 State canRaffleState = new CanRaffleState(this);
21 State dispenseState = new DispenseState(this);
22 State dispenseOutState = new DispenseOutState(this);
23
24 /**
25 * 构造器
26 * 1、初始化当前的状态为 noRaffleState 不能抽奖的状态
27 * 2、初始化奖品的数量
28 * @param count
29 */
30 public RaffleActivity(int count) {
31 this.state = getNoRaffleState();
32 this.count = count;
33 }
34
35 /**
36 * 扣分,调用当前状态的 deductMoney
37 */
38 public void debuctMoney() {
39 state.deductMoney();
40 }
41
42 /**
43 * 抽奖
44 */
45 public void raffle() {
46 //如果当前的状态是抽奖成功
47 if (state.raffle()) {
48 //领取奖品
49 state.dispensePrize();
50 }
51 }
52
53
54
55
56
57 public State getState() {
58 return state;
59 }
60
61 public void setState(State state) {
62 this.state = state;
63 }
64
65
66 /**
67 * 注意:每领取一次奖品,count--
68 * @param
69 */
70 public int getCount() {
71 int curCount = count;
72 count--;
73 return curCount;
74 }
75
76 public void setCount(int count) {
77 this.count = count;
78 }
79
80 public State getNoRaffleState() {
81 return noRaffleState;
82 }
83
84 public void setNoRaffleState(State noRaffleState) {
85 this.noRaffleState = noRaffleState;
86 }
87
88 public State getCanRaffleState() {
89 return canRaffleState;
90 }
91
92 public void setCanRaffleState(State canRaffleState) {
93 this.canRaffleState = canRaffleState;
94 }
95
96 public State getDispenseState() {
97 return dispenseState;
98 }
99
100 public void setDispenseState(State dispenseState) {
101 this.dispenseState = dispenseState;
102 }
103
104 public State getDispenseOutState() {
105 return dispenseOutState;
106 }
107
108 public void setDispenseOutState(State dispenseOutState) {
109 this.dispenseOutState = dispenseOutState;
110 }
111 }
客户端:
1 public class Client {
2 public static void main(String[] args) {
3 RaffleActivity activity = new RaffleActivity(1);
4
5 for (int i = 0; i < 30; i++) {
6 System.out.println("-----第" + (i + 1) + "次抽奖-----");
7 //参加抽奖,第一步点击扣除积分
8 activity.debuctMoney();
9
10 //第二步抽奖
11 activity.raffle();
12 }
13 }
14 }