優(yōu)秀程序員早就學會用“狀態(tài)模式”代替if-else了
2020年已經進入倒計時了,大家立好的flag完成了嗎?2020實“鼠”不易,希望2021可以“牛”轉乾坤。
簡介
狀態(tài)模式是行為型設計模式的一種。其設計理念是當對象的內部狀態(tài)發(fā)生改變時,隨之改變其行為。狀態(tài)和行為之間是一一對應的。
該模式主要用于,對象的行為依賴于它的狀態(tài),并且其行為是隨著狀態(tài)的改變而切換時。
狀態(tài)模式UML類圖

類圖講解
State:抽象狀態(tài)接口(也可以定義成抽象類),該接口封裝了所有狀態(tài)所對應的行為。
ConcreteStateA/B:具體狀態(tài)類,該類實現了抽象狀態(tài)接口,會根據自身對應的狀態(tài)來實現接口中定義的方法,還有另一個功能是指明如何過渡到下一個狀態(tài)。
Context:環(huán)境(上下文)角色,該類負責狀態(tài)的切換,還持有一個State實例,代表當前環(huán)境所處狀態(tài)。
案例講解
案例:通過狀態(tài)模式來實現自助售賣機的功能。
狀態(tài)接口
- public interface State {
- // 挑選商品
- void choose();
- // 付款
- boolean payment();
- // 分發(fā)商品
- void dispenseCommodity();
- }
挑選商品狀態(tài)類
- 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("請先挑選商品!");
- }
- }
付款狀態(tài)類
- 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("請先完成支付!");
- }
- }
商品售罄狀態(tài)類
- 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("對不起商品已售罄!");
- }
- }
分發(fā)商品狀態(tài)類
- 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 {
- // 表示當前狀態(tài)
- 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()) {
- // 分發(fā)商品
- 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();
- }
- }
- }
執(zhí)行結果

總結
1、狀態(tài)模式將每個狀態(tài)所對應的行為封裝到一個類中,大大提高了代碼的可讀性。并且通過這樣的設計還可以消除多余的if-else語句,方便代碼的維護。
2、狀態(tài)模式符合“開閉原則”,容易增加和刪除狀態(tài)。
3、任何事情都有利弊,狀態(tài)模式也不例外。其最顯著的問題是,每個狀態(tài)都要對應一個類,當狀態(tài)過多時會產生大量的類,從而加大維護成本。
4、應用場景:當一個需求有很多狀態(tài),并且狀態(tài)之間會進行轉換,不同狀態(tài)還對應不同的行為時就可以考慮使用“狀態(tài)模式”