原文地址:LoveDev
一个对象的行为其属性的动态变化,这样的属性叫状态,这类对象也叫做有状态的对象。当此类对象被某一事件修改其内部状态时,程序的行为也要随之改变
状态模式又称状态对象模式(Pattern of Objects for States)是用于解决对象的复杂状态及不同状态下的行为的一种模式。
模式定义
状态模式允许一个对象在其内部属性改变的时候改变其行为,这个对象看上去就像是改变了它的类一样
模式结构
状态模式涉及角色:
- 环境角色(Context):定义客户感兴趣的接口,并保留一个具体状态类的实例
- 抽象状态角色(State):定义一个借口,封装特定状态下的对应行为
- 具体状态角色(ConcreteState):抽象状态角色的子类,每个子类实现了相关的行为
Tip:
- 该图为UML图
- 类包含3个组成部分,第一栏为类名,第二栏为属性,第三栏为方法
- 属性和方法前可加一个可见性修饰符,
+
号表示public
修饰符,-
号表示private
修饰符,#
号表示protected
修饰符,省略表示包级可见。 - 接口包含2个组成部分,第一栏为接口名,第二栏为方法,在接口名之上加上
<<interface>>
使用场景
比如游戏中一个用户的用过外挂违规次数属性,如果用户用过1~3次,每次警告制裁;3次以上,每次封号3天;5次以上,每次封号1周;到达10次,永久封号。
根据以上描述可以分为四种状态:
- 警告
- 封号3天
- 封号1周
- 永久封号
源码
环境角色
public class PunishManager {
//保存违规用户及次数
private Map<String, Integer> mPunishMap = new HashMap<>();
/**
* 获取违规用户及次数
*/
Map<String, Integer> getPunishMap() {
return mPunishMap;
}
/**
* 获取具体状态角色,封装转换规则
*
* @param oldPunishCount 违规次数
* @return 具体状态角色
*/
private PunishState getPunishState(Integer oldPunishCount) {
//推荐尽量少用else,如果超过3层if-else代码推荐使用卫语句
if (oldPunishCount <= 3) {
return new LowPunishState();
}
if (oldPunishCount <= 5) {
return new MidPunishState();
}
if (oldPunishCount < 10) {
return new HeightPunishState();
}
return new BlackPunishState();
}
/**
* 违规处理
*
* @param uid 用户ID
*/
public void punish(String uid) {
//获取之前违规次数
Integer oldPunishCount = mPunishMap.get(uid);
if (oldPunishCount == null) {
oldPunishCount = 0;
}
oldPunishCount += 1;
mPunishMap.put(uid, oldPunishCount);
//获取对应状态对象进行响应操作
getPunishState(oldPunishCount).punish(uid, oldPunishCount, this);
}
}
抽象状态角色
public interface PunishState {
/**
* 违规处理
*
* @param uid 用户ID
* @param violationCount 违规次数
* @param punishManager 环境角色
*/
public void punish(String uid, int violationCount, PunishManager punishManager);
}
具体状态角色
根据不同的具体状态角色做相应的业务
public class LowPunishState implements PunishState {
@Override
public void punish(String uid, int violationCount, PunishManager punishManager) {
//违规1~3次,警告制裁
System.out.println("警告制裁");
}
}
public class MidPunishState implements PunishState {
@Override
public void punish(String uid, int violationCount, PunishManager punishManager) {
//违规3次以上,封号三天
System.out.println("封号三天");
}
}
public class HeightPunishState implements PunishState {
@Override
public void punish(String uid, int violationCount, PunishManager punishManager) {
//违规5次以上,封号一周
System.out.println("封号一周");
}
}
public class BlackPunishState implements PunishState {
@Override
public void punish(String uid, int violationCount, PunishManager punishManager) {
//违规10次,永久封号
System.out.println("永久封号");
}
}
入口类
public class Main {
public static void main(String[] args) {
PunishManager punishManager = new PunishManager();
for (int i = 1; i <= 10; i++) {
punishManager.punish("Kevin");
}
}
}
运行结果:
优点
- 封装了转换规则
- 结构清晰,提高可维护性
- 不同状态对应的不同行为放到单独类中,方便增加新的状态,只需改变对象状态即可改变对象行为
缺点
- 增加了类和对象的个数
- 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。