文章目录
- 状态模式
- 1.状态模式的本质
- 2.何时选用状态模式
- 3.优缺点
- 4.状态模式的结构
- 5.实现
- 上下文中维护状态及转换状态
- 上下文中维护状态处理类中转换状态
状态模式
状态模式说白了就是不同的状态,执行不同的行为,也就是状态和行为分离
1.状态模式的本质
状态模式的本质:根据状态来分离和选择行为。
仔细分析状态模式的结构,如果没有上下文,那么就退化回到只有接口和实现了,正是通过接口,把状态和状态对应的行为分开,才使得通过状态模式设计的程序易于扩展和维护。
而上下文主要负责的是公共的状态驱动,每当状态发生改变的时候,通常都是回调上下文来执行状态对应的功能。当然,上下文自身也可以维护状态的变化,另外,上下文通常还会作为多个状态处理类之间的数据载体,在多个状态处理类之间传递数据。
2.何时选用状态模式
建议在以下情况中选用状态模式。.
-
如果一个对象的行为取决于它的状态,而且它必须在运行时刻根据状态来改变它的行为,可以使用状态模式,来把状态和行为分离开。虽然分离开了,但状态和行为是有对应关系的,可以在运行期间,通过改变状态,就能够调用到该状态对应的状态处理对象上去,从而改变对象的行为。
-
如果一个操作中含有庞大的多分支语句,而且这些分支依赖于该对象的状态,可以使用状态模式,把各个分支的处理分散包装到单独的对象处理类中,这样,这些分支对应的对象就可以不依赖于其他对象而独立变化了。
3.优缺点
状态模式有以下优点。
-
简化应用逻辑控制
状态模式使用单独的类来封装一个状态的处理。如果把一个大的程序控制分成很多小块,每块定义一个状态来代表,那么就可以把这些逻辑控制的代码分散到很多单独的状态类中去,这样就把着眼点从执行状态提高到整个对象的状态,使得代码结构化和意图更清晰,从而简化应用的逻辑控制。
对于依赖于状态的if-else,理论上来讲,也可以改变成应用状态模式来实现,把每个if 或else块定义一个状态来代表,那么就可以把块内的功能代码移动到状态处理类中,从而减少if-else,避免出现巨大的条件语句。 -
更好地分离状态和行为
状态模式通过设置所有状态类的公共接口,把状态和状态对应的行为分离开,把所有与一个特定的状态相关的行为都放入一个对象中,使得应用程序在控制的时候,只需要关心状态的切换,而不用关心这个状态对应的真正处理。 -
更好的扩展性
引入了状态处理的公共接口后,使得扩展新的状态变得非常容易,只需要新增加一个实现状态处理的公共接口的实现类,然后在进行状态维护的地方,设置状态变化到这个新的状态即可。 -
显式化进行状态转换
状态模式为不同的状态引入独立的对象,使得状态的转换变得更加明确。而且状态对象可以保证上下文不会发生内部状态不一致的情况,因为上下文中只有一个变量来记录状态对象,只要为这一个变量赋值就可以了。
状态模式也有一个很明显的缺点,一个状态对应一个状态处理类,会使得程序引入太多的状态类,这样程序变得杂乱。
4.状态模式的结构
- Context:环境,也称上下文,通常用来定义客户感兴趣的接口,同时维护一个来具体处理当前状态的实例对象。
- State:状态接口,用来封装与上下文的一个特定状态所对应的行为。
- ConcreteState:具体实现状态处理的类,每个类实现一个跟上下文相关的状态的具体处理。
5.实现
上下文中维护状态及转换状态
这里用一个借钱的例子:
- 借钱3次以下:对方会告诉你没钱
- 借钱3次-5次:对方不回你消息
- 借钱5次以上:对方拉黑你
借钱接口及其实现
/**
* @description:借钱状态接口
*/
public interface BorrowState {
/**
* 借钱
* @param user 用户
* @param stateManager 状态管理器
*/
void borrowMoney(String user,StateManager stateManager);
}
/**
* @description:正常借钱(3次以下)
*/
public class NormalBorrowState implements BorrowState{
@Override
public void borrowMoney(String user,StateManager stateManager) {
System.out.println("对方也没钱啊-,-");
}
}
/**
* @description:重复借钱(3-5次)
*/
public class RepeatBorrowState implements BorrowState{
@Override
public void borrowMoney(String user,StateManager stateManager) {
System.out.println("对方表示不想回你消息了-,-");
}
}
/**
* @description:恶意借钱(5次以上)
*/
public class BlackBorrowState implements BorrowState{
@Override
public void borrowMoney(String user,StateManager stateManager) {
System.out.println("您已被对方拉黑-,-");
}
}
状态管理器
/**
* @description:状态管理器(context)
*/
public class StateManager {
private BorrowState borrowState;
//用户,借钱次数
private Map<String, Integer> countMap = new HashMap<>();
public void borrow(String user) {
Integer count = countMap.get(user);
if (count == null) {
count = 0;
}
//次数+1
count++;
countMap.put(user, count);
//先判断当前状态,根据状态转换不同的行为
if (count >= 1 && count < 3) {
borrowState = new NormalBorrowState();
} else if (count >= 3 && count < 5) {
borrowState = new RepeatBorrowState();
} else if (count >= 5) {
borrowState = new BlackBorrowState();
}
this.borrowState.borrowMoney(user, this);
}
}
测试类
public class Client {
public static void main(String[] args) {
StateManager stateManager = new StateManager();
for (int i = 0; i < 10; i++) {
stateManager.borrow("张三");
}
}
}
结果
上下文中维护状态处理类中转换状态
借钱接口没变,修改其实现类
/**
* @description:正常借钱(3次以下)
*/
public class NormalBorrowState implements BorrowState {
@Override
public void borrowMoney(String user, StateManager stateManager) {
System.out.println("对方也没钱啊-,-");
//取出状态,根据状态转换行为
Integer count = stateManager.getCountMap().get(user);
if (count >= 2 && count < 5) {
stateManager.getStateMap().put(user, new RepeatBorrowState());
}
}
}
/**
* @description:重复借钱(3-5次)
*/
public class RepeatBorrowState implements BorrowState{
@Override
public void borrowMoney(String user,StateManager stateManager) {
System.out.println("对方表示不想回你消息了-,-");
Integer count = stateManager.getCountMap().get(user);
if (count >= 5) {
stateManager.getStateMap().put(user, new BlackBorrowState());
}
}
}
/**
* @description:恶意借钱(5次以上)
*/
public class BlackBorrowState implements BorrowState{
@Override
public void borrowMoney(String user,StateManager stateManager) {
System.out.println("您已被对方拉黑-,-");
}
}
状态管理器
/**
* @description:状态管理器(context)
*/
@Getter
public class StateManager {
//用户,借钱次数
private Map<String, Integer> countMap = new HashMap<>();
//用户,要执行的行为
private Map<String, BorrowState> stateMap = new HashMap<>();
public void borrow(String user) {
Integer count = countMap.get(user);
if (count == null) {
count = 0;
}
//次数+1
count++;
//放入状态
countMap.put(user, count);
//取出行为
BorrowState borrowState = stateMap.get(user);
if (borrowState == null) {
borrowState = new NormalBorrowState();
}
borrowState.borrowMoney(user, this);
}
}
测试类
public class Client {
public static void main(String[] args) {
StateManager stateManager = new StateManager();
for (int i = 0; i < 10; i++) {
stateManager.borrow("张三");
}
}
}
结果