【设计模式】状态模式

来源:互联网 发布:掌上贵金属软件下载 编辑:程序博客网 时间:2024/04/30 14:43

状态模式定义:当一个对象内在状态改变时运行其改变行为,这个对象看起来像改变了其类。

    在我们if else超过3层的时候,很多时候我们会想到状态模式,其可以使代码结构看起来更清晰也利于扩展,其核心就是封装性,将状态的改变封装起来,客户端不用关心状态的改变,但是实际内部是有状态的转换的。

    首先依旧是假定一个场景:我们平常玩网游的时候都会有杀人系统,这里简化一下,玩家分为白名,黄名,红名玩家。白名玩家是不可以杀人和被杀的,但是可以手动开启PK,则会进入黄名状态;黄名状态可以杀别的玩家,杀人后变成红名状态,但是杀人前还是黄名状态时不可以被别的玩家杀害;红名玩家可以杀人和被杀,被杀后状态变为黄名。这就是一个很典型的状态模式的例子,如果不用状态模式,我们在杀人、被杀、状态转换这些方法中都要加if else来判断玩家当前状态进行不同的处理,代码会很难看且臃肿,用状态模式则会清晰很多,下面来看类图:

状态模式

    从图中可以看到,本例分为三种状态WhitePlayer、YellowPlayer、RedPlayer,其只需要管自己状态时内部三个方法的实现即可,下面来看具体实现:

    状态接口IState

public interface IState {    /**     * 击杀其他玩家     */    void killPlayer();    /**     * 被其他玩家击杀     */    void beKilled();    /**     * 更改状态     */    void transferState();}

    玩家状态抽象类PlayerState

public abstract class PlayerState implements IState {    protected Context context;    public void setContext(Context context) {        this.context = context;    }    @Override    public abstract void killPlayer();    @Override    public abstract void beKilled();    @Override    public abstract void transferState();}

    白名玩家实现类WhitePlayer

public class WhitePlayer extends PlayerState {    @Override    public void killPlayer() {        System.out.println("白名玩家不能击杀其他玩家");    }    @Override    public void beKilled() {        System.out.println("白名玩家不可以被其他玩家击杀");    }    /**     * 白名玩家可以自己手动开启PK模式,状态变为黄名玩家     */    @Override    public void transferState() {        super.context.setPlayerState(new YellowPlayer());        System.out.println("我开启了PK模式,变成了黄名玩家!");    }}

    黄名玩家实现类YellowPlayer

public class YellowPlayer extends PlayerState {    /**     * 黄名玩家可以击杀其他玩家,击杀后玩家变成红名玩家     */    @Override    public void killPlayer() {        System.out.println("我杀人啦!!!!!!!");        super.context.setPlayerState(new RedPlayer());    }    @Override    public void beKilled() {        System.out.println("黄名玩家不可以被其他玩家击杀");    }    /**     * 黄名玩家可以自己关闭PK模式,状态变为白名玩家     */    @Override    public void transferState() {        super.context.setPlayerState(new WhitePlayer());        System.out.println("我关闭了PK模式,变成了白名玩家!");    }}

    红名玩家实现类RedPlayer

public class RedPlayer extends PlayerState {    /**     * 红名玩家可以击杀其他玩家     */    @Override    public void killPlayer() {        System.out.println("我杀了很多人啦!!!!");    }    /**     * 红名玩家可以被其他玩家击杀,击杀后变为黄名     */    @Override    public void beKilled() {        System.out.println("我被杀了!!!so sad!!!");        super.context.setPlayerState(new YellowPlayer());    }    /**     * 红名玩家不能主动转换状态     */    @Override    public void transferState() {        System.out.println("我不能转换自己的状态了!");    }}

    场景控制类Context

public class Context implements IState {    private PlayerState playerState;    public void setPlayerState(PlayerState playerState) {        this.playerState = playerState;        playerState.setContext(this);    }    @Override    public void killPlayer() {        playerState.killPlayer();    }    @Override    public void beKilled() {        playerState.beKilled();    }    @Override    public void transferState() {        playerState.transferState();    }}

    下面来看客户端代码,很简单

public static void main(String[] args) {    Context context = new Context();    // 玩家初始都是白名玩家    context.setPlayerState(new WhitePlayer());    // 白名玩家尝试杀人    context.killPlayer();    // 不行,我要开启PK杀人    context.transferState();    // 刚开了PK还没杀人呢,就有人想杀我    context.beKilled();    // 我去杀人了    context.killPlayer();    // 有人来杀我了    context.beKilled();    // 被杀了,还是白名安全    context.transferState();    // oh yeah ,不能被杀了    context.beKilled();}

    运行结果如下:

白名玩家不能击杀其他玩家我开启了PK模式,变成了黄名玩家!黄名玩家不可以被其他玩家击杀我杀人啦!!!!!!!我被杀了!!!so sad!!!我关闭了PK模式,变成了白名玩家!白名玩家不可以被其他玩家击杀

    可以看到,客户端是不关心内部状态的改变的,只需要按照我们平常的操作流程进行操作而已,通篇没有一个if else,代码看起来很清晰。

    总结:

优点

  1. 结构清晰,避免出现过多臃肿的if else。
  2. 封装性强,客户端无需关心状态的转换。
  3. 易于扩展,显然新增一种状态要比每个方法中都加一层else if要容易的多。

缺点:每个状态对应一个类,状态越多类越多,可能会造成类过多。


欢迎关注个人博客:blog.scarlettbai.com

0 0
原创粉丝点击