設計模式,行爲模式之狀態模式

1 概述

狀態模式(state Pattern)是行爲模式之一,一般用在對象的行爲依賴於內部狀態的場景。

2 狀態模式

考慮一個場景:對象有狀態,而且根據狀態不同,對象的行爲也會不同。對於該情況,最簡單的方式是,對狀態做if-else或者swith-case判斷,根據狀態調用相應的行爲。但是這種做法,把對象和狀態耦合在了一起,難於擴展和維護。更好的做法是,用狀態模式將狀態抽離出來形成一個接口,而目標對象依賴該狀態接口,來完成對應的行爲,由此達到解耦的目的。
狀態模式策略模式非常相像,可視爲策略模式的擴展。兩者都基於組合機制,通過將部分工作委派給另外的對象來改變其在不同情景下的行爲。不同的是,策略模式中這些對象相互之間完全獨立,不知道彼此的存在。但狀態模式沒有限制具體狀態之間的依賴,且允許它們自行改變在不同情景下的狀態。

3 案例

結合例子,來進一步理解狀態模式
一個人的戰鬥力,在飢餓狀態和發怒狀態下是不同的,所以“戰鬥的行爲”依賴於“身體的狀態”,最簡單的做法如下:

public class Fighter {
    private String mode = "normal";
    public void setMode(String mode) {
        this.mode = mode;
    }
    public void fight() {
        if (mode.equalsIgnoreCase("angry")) {
            System.out.println("Fighting with power 200 on angry mode!!!");
        }
        else if (mode.equalsIgnoreCase("hungry")) {
            System.out.println("Fighting with power 50 on mode hungry...");
        }
        else {
            System.out.println("Fighting with power 100 normal mode!");
        }
    }
}

簡單的if-else塊,根據狀態控制行爲。但是這種寫法不容易維護,每當狀態需要修改/新增/刪除,都需要改動Fighter類;而且當狀態越來越多的時候,方法體會變得越來越龐大,可讀性很低。下面看看用狀態模式如何操作:

public interface State {
    void fight();
}
public class NormalState implements State {
    @Override
    public void fight() {
        System.out.println("Fighting with power 100 normal mode!");
    }
}
public class HungryState implements State {
    @Override
    public void fight() {
        System.out.println("Fighting with power 50 on mode hungry...");
    }
}
public class AngryState implements State {
    @Override
    public void fight() {
        System.out.println("Fighting with power 200 on angry mode!!!");
    }
}

public class Fighter implements State {
    private State state = new NormalState();

    public void setState(State state) {
        this.state = state;
    }
    public State getState() {
        return state;
    }
    @Override
    public void fight() {
        state.fight();
    }
}

public class Test {
    public static void main(String[] args) {
        Fighter luffy = new Fighter();
        State hungryState = new HungryState();
        State angryState = new AngryState();

        luffy.fight();

        luffy.setState(hungryState);
        luffy.fight();

        luffy.setState(angryState);
        luffy.fight();
    }
}

輸出:

Fighting with power 100 normal mode!
Fighting with power 50 on mode hungry...
Fighting with power 200 on angry mode!!!

我們將“狀態”從對象中抽離出來,做成一個單獨的接口State,並將對象的行爲放到State的實現類中。這種模式,無論是擴展性還是可維護性,都高於前面那種方式,這就是狀態模式的威力。

4 總結

狀態模式使得對象與其狀態分離解耦,使得代碼邏輯更加靈活健壯。當對象的行爲依賴於內部狀態時,不要一昧地用if-else,可以考慮使用狀態模式

文中例子的github地址

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