作爲優秀程序員早就學會用“狀態模式”代替if-else了 簡介 狀態模式UML類圖 案例講解 總結

2020年已經進入倒計時了,大家立好的flag完成了嗎?2020實“鼠”不易,希望2021可以“牛”轉乾坤。

簡介

狀態模式是行爲型設計模式的一種。其設計理念是當對象的內部狀態發生改變時,隨之改變其行爲。狀態和行爲之間是一一對應的。

該模式主要用於,對象的行爲依賴於它的狀態,並且其行爲是隨着狀態的改變而切換時。

狀態模式UML類圖

類圖講解

State:抽象狀態接口(也可以定義成抽象類),該接口封裝了所有狀態所對應的行爲。
ConcreteStateA/B:具體狀態類,該類實現了抽象狀態接口,會根據自身對應的狀態來實現接口中定義的方法,還有另一個功能是指明如何過渡到下一個狀態。
Context:環境(上下文)角色,該類負責狀態的切換,還持有一個State實例,代表當前環境所處狀態。

案例講解

案例:通過狀態模式來實現自助售賣機的功能。

狀態接口

public interface State {
  // 挑選商品
  void choose();
  // 付款
  boolean payment();
  // 分發商品
  void dispenseCommodity();
}

挑選商品狀態類

public class ChooseGoods implements State {

  VendingMachine machine;

  public ChooseGoods(VendingMachine machine) {
    this.machine = machine;
  }

  @Override
  public void choose() {
    if (machine.getCount() > 0) {
      System.out.println("商品挑選成功,請及時付款!");
      machine.setState(machine.getPaymentState());
    } else {
      System.out.println("很遺憾,商品售罄了!");
      machine.setState(machine.getEmptyState());
    }
  }

  @Override
  public boolean payment() {
    System.out.println("請先挑選商品!");
    return false;
  }

  @Override
  public void dispenseCommodity() {
    System.out.println("請先挑選商品!");
  }
}

付款狀態類

public class PaymentState implements State {

  VendingMachine machine;

  public PaymentState(VendingMachine machine) {
    this.machine = machine;
  }

  @Override
  public void choose() {
    System.out.println("商品已選購完成請勿重複挑選");
  }

  @Override
  public boolean payment() {
    Random random = new Random();
    int num = random.nextInt(10);
    if(num % 2 == 0){
      System.out.println("付款成功!");
      machine.setState(machine.getDispenseCommodityState());
      return true;
    }
    System.out.println("付款失敗,請重新支付!");
    return false;
  }

  @Override
  public void dispenseCommodity() {
    System.out.println("請先完成支付!");
  }
}

商品售罄狀態類

public class EmptyState implements State {

  VendingMachine machine;

  public EmptyState(VendingMachine machine) {
    this.machine = machine;
  }

  @Override
  public void choose() {
    System.out.println("對不起商品已售罄!");
  }

  @Override
  public boolean payment() {
    System.out.println("對不起商品已售罄!");
    return false;
  }

  @Override
  public void dispenseCommodity() {
    System.out.println("對不起商品已售罄!");
  }
}

分發商品狀態類

public class DispenseCommodityState implements State {

  VendingMachine machine;

  public DispenseCommodityState(VendingMachine machine) {
    this.machine = machine;
  }

  @Override
  public void choose() {
    System.out.println("請及時取走您的商品!");
  }

  @Override
  public boolean payment() {
    System.out.println("請及時取走您的商品!");
    return false;
  }

  @Override
  public void dispenseCommodity() {
    System.out.println("請及時取走您的商品!");
    machine.setState(machine.getChooseGoods());
  }
}

自動售貨機 => Context角色

public class VendingMachine {
  // 表示當前狀態
  private State state = null;
  // 商品數量
  private int count = 0;
  private State chooseGoods = new ChooseGoods(this);
  private State paymentState = new PaymentState(this);
  private State dispenseCommodityState = new DispenseCommodityState(this);
  private State emptyState = new EmptyState(this);

  public VendingMachine(int count) {
    this.count = count;
    this.state = this.getChooseGoods();
  }

  // 購買商品
  public void purchase() {
    // 挑選商品
    state.choose();
    // 支付成功
    if (state.payment()) {
      // 分發商品
      state.dispenseCommodity();
    }
  }

  // 獲取商品後將商品減一
  public int getCount() {
    return count--;
  }

  // get和set方法 ... 
}

客戶端測試類

public class Client {

  public static void main(String[] args) {
    VendingMachine machine = new VendingMachine(1);
    for (int i = 1; i < 4; i++) {
      System.out.println("第" + i + "次購買。");
      machine.purchase();
    }
  }
}

執行結果

總結

1、狀態模式將每個狀態所對應的行爲封裝到一個類中,大大提高了代碼的可讀性。並且通過這樣的設計還可以消除多餘的if-else語句,方便代碼的維護。

2、狀態模式符合“開閉原則”,容易增加和刪除狀態。

3、任何事情都有利弊,狀態模式也不例外。其最顯著的問題是,每個狀態都要對應一個類,當狀態過多時會產生大量的類,從而加大維護成本。

4、應用場景:當一個需求有很多狀態,並且狀態之間會進行轉換,不同狀態還對應不同的行爲時就可以考慮使用“狀態模式”。

今天的分享就到這裏了,如果感覺“菜鳥”寫的文章還不錯,記得點贊、轉發加關注呦!你們的支持就是我堅持下去的動力。文章哪裏寫的有問題的也希望大家可以指出,我會虛心受教。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章