博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【设计模式】状态模式
阅读量:4079 次
发布时间:2019-05-25

本文共 3781 字,大约阅读时间需要 12 分钟。

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

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

你可能感兴趣的文章
剑指_顺时针打印矩阵
查看>>
剑指_栈的压入弹出序列
查看>>
剑指_复杂链表的复制
查看>>
服务器普通用户(非管理员账户)在自己目录下安装TensorFlow
查看>>
星环后台研发实习面经
查看>>
大数相乘不能用自带大数类型
查看>>
字节跳动后端开发一面
查看>>
CentOS Tensorflow 基础环境配置
查看>>
centOS7安装FTP
查看>>
FTP的命令
查看>>
CentOS操作系统下安装yum的方法
查看>>
ping 报name or service not known
查看>>
FTP 常见问题
查看>>
zookeeper单机集群安装
查看>>
do_generic_file_read()函数
查看>>
Python学习笔记之数据类型
查看>>
Python学习笔记之特点
查看>>
shell 快捷键
查看>>
VIM滚屏操作
查看>>
EMC 2014存储布局及十大新技术要点
查看>>