【设计模式】状态模式

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

    在我们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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值