趣談狀態模式

全文一共1543字,預計閱讀時間10分鐘程序員

定義:

  狀態模式(State),當一個對象的內在狀態改變時容許改變其行爲,這個對象看起來像是改變了其類。
  只看這個定義的話,想必會一頭霧水,其實狀態模式解決的問題是:
  當控制了一個對象狀態轉換的表達式過於複雜時,咱們能夠把狀態的判斷邏輯轉移到表示不一樣狀態的一系列的類中。這樣作可使複雜的判斷邏輯簡化,同時使類的職責更加單一。

實例:

  假設每個程序員會對應一個經驗值(empiricalValue),咱們會根據這個程序員的經驗值,來評定這個程序員的職稱,如MT,開發助理,初級程序員,中級程序員,高級程序員,專家。那麼讓你來完成這個程序,你會如何設計你的代碼呢?
  相信有一部分人會寫出和我同樣的代碼:
**
 * 程序員類.
 *
 * @author jialin.li
 * @date 2019-12-30 17:38
 */
public class Programmer {
    private int empiricalValue;

    public void setEmpiricalValue(int empiricalValue) {
        this.empiricalValue = empiricalValue;
    }

    public void evaluate() {
        if(empiricalValue < 100){
            System.out.println("MT");
        }else if(empiricalValue < 200){
            System.out.println("開發助理");
        }else if(empiricalValue < 300){
            System.out.println("初級程序員");
        }else if(empiricalValue < 400){
            System.out.println("中級程序員");
        }else if(empiricalValue < 500){
            System.out.println("高級程序員");
        }else if(empiricalValue < 600){
            System.out.println("技術專家");
        }
    }
}
/**
 * 客戶端.
 *
 * @author jialin.li
 * @date 2019-12-30 18:28
 */
public class Main {
    public static void main(String[] args) {
        Programmer programmer = new Programmer();
        programmer.setEmpiricalValue(50);
        programmer.evaluate();
        programmer.setEmpiricalValue(150);
        programmer.evaluate();
        programmer.setEmpiricalValue(250);
        programmer.evaluate();
        programmer.setEmpiricalValue(350);
        programmer.evaluate();
        programmer.setEmpiricalValue(450);
        programmer.evaluate();
        programmer.setEmpiricalValue(550);
        programmer.evaluate();
    }
}

結果:

MT
開發助理
初級程序員
中級程序員
高級程序員
技術專家

這樣的代碼有什麼問題?

  首先,evaluate方法充斥着大量的if/else,這個時候就要警戒,由於大量的if/else每每表明了該代碼不符合開閉原則,每次修改或者新增條件,都會對原來的代碼產生影響。
  其次,evaluate方法比較長,在面向對象編程中,方法的設計應該是短小且功能單一的,較長的方法每每意味着該方法不符合單一職責原則,或者是須要進行抽象。
  實際上,這段代碼是用面嚮對象語言寫出的面向過程的代碼。這也是軟件開發中常見的誤區之一,並非使用面嚮對象語言,寫出的代碼就是面向對象代碼。
這個時候應該如何對上述代碼進行優化?這就引出了咱們今天要介紹的設計模式:狀態模式,狀態模式的結構相對簡單,可是用法卻十分巧妙:

 

 
  這裏將狀態模式對應到咱們的實例中,對經驗值的斷定和處理,能夠被封裝成一個個ConcreteState,將他們的處理方法抽象出來,就是State,而Context則起到一個維護當前狀態的做用,接下來是咱們修改後的代碼:

代碼:

/**
 * 狀態處理接口.
 *
 * @author jialin.li
 * @date 2019-12-30 19:23
 */
public interface State {
    void handle(Programmer programmer);
}
/**
 * 程序員類.
 *
 * @author jialin.li
 * @date 2019-12-30 17:38
 */
public class Programmer {
    /**
     * 經驗值
     */
    private int empiricalValue;
    /**
     * 當前狀態
     */
    private State state = new MTState();


    public void setEmpiricalValue(int empiricalValue) {
        this.empiricalValue = empiricalValue;
    }

    public int getEmpiricalValue() {
        return empiricalValue;
    }

    public void setState(State state) {
        this.state = state;
    }

    public void handle() {
        state.handle(this);
    }
}
/**
 * MT.
 *
 * @author jialin.li
 * @date 2019-12-30 19:30
 */
public class MTState implements State {
    @Override
    public void handle(Programmer programmer) {
        int empiricalValue = programmer.getEmpiricalValue();
        if (empiricalValue < 100) {
            System.out.println("MT");
        } else {
            State juniorProgrammer = new JuniorProgrammer();
            programmer.setState(juniorProgrammer);
            juniorProgrammer.handle(programmer);
        }
    }
}
/**
 * 助理程序員.
 *
 * @author jialin.li
 * @date 2019-12-30 19:33
 */
public class ProgrammerAssistant implements State{
    @Override
    public void handle(Programmer programmer) {
        int empiricalValue = programmer.getEmpiricalValue();
        if(empiricalValue < 200){
            System.out.println("開發助理");
        }else{
            JuniorProgrammer juniorProgrammer = new JuniorProgrammer();
            programmer.setState(juniorProgrammer);
            juniorProgrammer.handle(programmer);
        }
    }
}
/**
 * 初級程序員.
 *
 * @author jialin.li
 * @date 2019-12-30 19:31
 */
public class JuniorProgrammer implements State {
    @Override
    public void handle(Programmer programmer) {
        int empiricalValue = programmer.getEmpiricalValue();
        if (empiricalValue < 300) {
            System.out.println("初級程序員");
        } else {
            State middleProgrammer = new MiddleProgrammer();
            programmer.setState(middleProgrammer);
            middleProgrammer.handle(programmer);
        }
    }
}
/**
 * 中級程序員.
 *
 * @author jialin.li
 * @date 2019-12-30 19:32
 */
public class MiddleProgrammer implements State {
    @Override
    public void handle(Programmer programmer) {
        int empiricalValue = programmer.getEmpiricalValue();
        if (empiricalValue < 400) {
            System.out.println("中級程序員");
        } else {
            SeniorProgrammer seniorProgrammer = new SeniorProgrammer();
            programmer.setState(seniorProgrammer);
            seniorProgrammer.handle(programmer);
        }
    }
}
/**
 * 高級程序員.
 *
 * @author jialin.li
 * @date 2019-12-30 19:34
 */
public class SeniorProgrammer implements State {
    @Override
    public void handle(Programmer programmer) {
        int empiricalValue = programmer.getEmpiricalValue();
        if (empiricalValue < 500) {
            System.out.println("高級程序員");
        } else {
            Professor professor = new Professor();
            programmer.setState(professor);
            professor.handle(programmer);
        }
    }
}
/**
 * @author jialin.li
 * @date 2019-12-30 19:35
 */
public class Professor implements State {
    @Override
    public void handle(Programmer programmer) {
        System.out.println("技術專家");
    }
}
/**
 * @author jialin.li
 * @date 2019-12-30 19:35
 */
public class Professor implements State {
    @Override
    public void handle(Programmer programmer) {
        System.out.println("技術專家");
    }
}
/**
 * 客戶端.
 *
 * @author jialin.li
 * @date 2019-12-30 19:36
 */
public class Main {
    public static void main(String[] args) {
        Programmer programmer = new Programmer();
        programmer.setEmpiricalValue(50);
        programmer.handle();
        programmer.setEmpiricalValue(150);
        programmer.handle();
        programmer.setEmpiricalValue(250);
        programmer.handle();
        programmer.setEmpiricalValue(350);
        programmer.handle();
        programmer.setEmpiricalValue(450);
        programmer.handle();
        programmer.setEmpiricalValue(550);
        programmer.handle();
    }
}

結果:

MT
初級程序員
初級程序員
中級程序員
高級程序員
技術專家
 
  能夠看出客戶端代碼基本沒有變化,服務端代碼變得更加靈活了。
  在Tomcat中,有一個LifecycleState枚舉類,用於描述組件的生命週期狀態,狀態變動的時候,會進行上一個狀態的判斷,從而肯定本次狀態變動是否合法,這種設計也能夠用在咱們的狀態模式中。
 
@Override
public final synchronized void init() throws LifecycleException {
    if (!state.equals(LifecycleState.NEW)) {
        invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
    }

    try {
        setStateInternal(LifecycleState.INITIALIZING, null, false);
        initInternal();
        setStateInternal(LifecycleState.INITIALIZED, null, false);
    } catch (Throwable t) {
        handleSubClassException(t, "lifecycleBase.initFail", toString());
    }
}
private void invalidTransition(String type) throws LifecycleException {
    String msg = sm.getString("lifecycleBase.invalidTransition", type, toString(), state);
    throw new LifecycleException(msg);
}
  其實萬變不離其宗,在設計模式中,這個宗指的就是各類設計原則。學習設計模式的時候,要時刻聯繫設計原則,有一種說法是,真正精通設計模式的時候,是忘記全部的設計模式(有一種張無忌學太極劍的感受)。

  期待您的關注、推薦、收藏,同時也期待您的糾錯和批評。編程

相關文章
相關標籤/搜索