狀態模式

這是一個轉變狀態的模式。

需求

設計一個線上購物程式,並設計以下幾種狀態。

  • 無訂單狀態
  • 訂購商品
  • 裝箱
  • 寄送商品
  • 接收產品

訂購產品的時候,由無訂單狀態 -> 訂購商品狀態 -> 裝箱狀態 -> 寄送狀態 -> 接收產品狀態 -> 無訂單狀態

類別圖

img

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

results matching ""

    No results matching ""