狀態模式
這是一個轉變狀態的模式。
需求
設計一個線上購物程式,並設計以下幾種狀態。
- 無訂單狀態
- 訂購商品
- 裝箱
- 寄送商品
- 接收產品
訂購產品的時候,由無訂單狀態 -> 訂購商品狀態 -> 裝箱狀態 -> 寄送狀態 -> 接收產品狀態 -> 無訂單狀態
類別圖
Eshopping
儲存共用的變數count,各種狀態(沒訂單狀態、訂單狀態、裝箱狀態、寄送狀態、收到狀態)、state為目前狀態。
- setState()設定目前狀態
- order() 呼叫orderState訂單狀態的order()
- box() 呼叫boxState裝箱狀態的box()
- delivery() 呼叫deliveryState寄送狀態的delivery()
- receiveState() 呼叫receiveState接收狀態的receive()
- noOrder() 呼叫noOrderState沒有訂單狀態的noOrder()
- setCount() 設定產品變數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
public class Eshopping {
// 沒訂單狀態
private State noOrderState;
// 訂單狀態
private State orderState;
// 裝箱狀態
private State boxState;
// 寄送狀態
private State deliveryState;
// 收到狀態
private State receiveState;
// 目前狀態
private State state;
// 產品數量
private int count = 0;
public Eshopping() {
// 建立所有狀態
noOrderState = new NoOrderState(this);
orderState = new OrderState(this);
boxState = new BoxState(this);
deliveryState = new DeliveryState(this);
receiveState = new ReceiveState(this);
// 預設為沒有訂單狀態
state = noOrderState;
}
// 沒有訂單
public void noOrder() {
state.noOrder();
}
// 訂購
public void order() {
state.order();
}
// 產品裝箱
public void box() {
state.box();
}
// 產品寄送
public void delivery() {
state.deliver();
}
// 收到產品
public void receive() {
state.receive();
}
// 設定狀態
public void setState(State state) {
this.state = state;
}
// 取得無訂單狀態
public State getNoOrderState() {
return noOrderState;
}
public State getOrderState() {
return orderState;
}
public State getBoxState() {
return boxState;
}
public State getDeliveryState() {
return deliveryState;
}
public State getReceiveState() {
return receiveState;
}
// 設定產品數量
public void setCount(int count) {
this.count = count;
}
//取得產品數量
public int getCount() {
return count;
}
}
State介面
定義介面要實作的方法
1
2
3
4
5
6
7
8
9
10
11
12
public interface State {
// 沒訂單
void noOrder();
// 訂購
void order();
// 裝箱
void box();
// 寄送
void deliver();
// 收到產品
void receive();
}
AbstractState抽象狀態
此處用到介面轉接器模式
把介面所有的方法全部實作,繼承的子類別,只要選擇性覆寫特定方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public abstract class AbstractState implements State {
@Override
public void noOrder() {
// do nothing
}
@Override
public void order() {
// do nothing
}
@Override
public void box() {
// do nothing
}
@Override
public void deliver() {
// do nothing
}
@Override
public void receive() {
// do nothing
}
}
無訂單狀態
重點在於轉換到其它狀態的部分,狀態轉到訂單狀態,並呼叫訂單狀態的order方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class NoOrderState extends AbstractState {
private Eshopping eshopping;
public NoOrderState(Eshopping eshopping) {
this.eshopping = eshopping;
}
@Override
public void noOrder() {
if (eshopping.getCount() == 0)
System.out.println("產品數量不足");
System.out.println("無訂單狀態");
}
@Override
public void order() {
// 狀態轉到訂單狀態
eshopping.setState(eshopping.getOrderState());
// 呼叫訂購
eshopping.order();
}
}
訂購狀態
重點在於轉換到其它狀態的部分,訂單狀態轉到裝箱狀態,並呼叫裝箱狀態的box()。
若產品數量不足,無法提供訂購,訂單狀態轉到沒有訂單,並呼叫沒有訂單狀態的noOrder()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class OrderState extends AbstractState {
private Eshopping eshopping;
public OrderState(Eshopping eshopping) {
this.eshopping = eshopping;
}
@Override
public void order() {
if (eshopping.getCount() > 0) {
System.out.println("訂購產品");
// 數量減1
eshopping.setCount(eshopping.getCount() - 1);
// 狀態轉到裝箱
eshopping.setState(eshopping.getBoxState());
eshopping.box();
} else {
// 狀態轉到沒有訂單
eshopping.setState(eshopping.getNoOrderState());
// 呼叫沒有訂單的方法
eshopping.noOrder();
}
}
}
裝箱狀態
重點在於轉換到其它狀態的部分,狀態轉到寄送狀態,並呼叫寄送狀態的delivery()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BoxState extends AbstractState{
private Eshopping eshopping;
public BoxState(Eshopping eshopping) {
this.eshopping = eshopping;
}
@Override
public void box() {
// 裝箱
System.out.println("裝箱完成");
// 狀態轉到寄送
eshopping.setState(eshopping.getDeliveryState());
eshopping.delivery();
}
}
寄送狀態
重點在於轉換到其它狀態的部分,狀態轉到接收狀態,並呼叫接收狀態的receivey()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class DeliveryState extends AbstractState {
private Eshopping eshopping;
public DeliveryState(Eshopping eshopping) {
this.eshopping = eshopping;
}
@Override
public void deliver() {
System.out.println("出貨");
// 狀態轉到接收
eshopping.setState(eshopping.getReceiveState());
eshopping.receive();
}
}
接收狀態
重點在於轉換到其它狀態的部分,狀態轉到沒有訂單狀態,並呼叫沒有訂單狀態的noOrder()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ReceiveState extends AbstractState {
private Eshopping eshopping;
public ReceiveState(Eshopping eshopping) {
this.eshopping = eshopping;
}
@Override
public void receive() {
System.out.println("貨品已送達");
// 狀態轉到沒有訂單
eshopping.setState(eshopping.getNoOrderState());
eshopping.noOrder();
}
}
測試
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
public static void main(String[] args) {
Eshopping eshopping = new Eshopping();
//設定數量
eshopping.setCount(2);
//訂購
eshopping.order();
System.out.println("===========================");
eshopping.order();
System.out.println("===========================");
eshopping.order();
}
}
訂購產品
裝箱完成
出貨
貨品已送達
商品剩餘數量 = 1
===========================
訂購產品
裝箱完成
出貨
貨品已送達
商品剩餘數量 = 0
===========================
產品數量不足
無訂單狀態
商品剩餘數量 = 0