Java设计模式超详解--状态设计模式
一,初步理解

图片来源:浏览器找的,不是作者本人画的
生活中的很多事物都具有不同的状态,如何让不同状态能够自如切换不出错,是我们今天要解决的问题。
举个例子:
生活中常见的旋转门(要收费那种)
假如转门处于锁定状态LockedTurnstileState:
当投币事件发生(coin()方法时,转门将转换到非锁定状态,并且执行解锁动作(Turnstile类的unLock()方法)。
假如转门处于非锁定状态UnLockedTurnstileState:
当有人通过门(pass()方法)时,转门将转换到锁定状态,并且将执行锁定动作(Turnstile类的lock()方法)。
当转门处于锁定状态,当有人通过门时 ,执行警告动作 (Turnstile类的alarm()方法)
当转门已经处于非锁定状态,当投币事件发生,执行谢谢动作(Turnstile类的thankYou()方法)
整理一下题目逻辑我们发现,大概是这个逻辑:

那大家肯定发现,一个简单的思维导图显然无法满足我们的逻辑需求(因为有一部分循环逻辑),所以为大家介绍状态图:

通过该状态图能更加清晰地看出我们的逻辑,接下来,结合我们刚刚讲到的类图,分析一下该题目的类图该怎么画:
首先
根据题目,很容易得到:
类图中的ContextState(具体状态)表示对应题目中的
LockedTurnstileState(表示锁住的状态)
UnLockedTurnstileState (表示未锁的状态)
那现在我们还需要写的是
State(与状态相关的行为)
作为ContextState(具体状态)的父类,需要写清楚状态行为的具体函数,如coin()与pass()
Context(当前状态)
需要写清楚当前状态的所有方法与行为
具体类图如下:

下面是详细代码实现
TurnstileState
/**
* 转门状态接口:定义转门所有状态需要实现的核心行为(投币、通过)
* 状态模式的核心:将不同状态的行为封装到各自的实现类中,转门类仅负责状态切换
*/
interface TurnstileState {
/**
* 投币行为:不同状态下投币的处理逻辑不同,由具体状态类实现
*/
void coin();
/**
* 通行行为:不同状态下通行的处理逻辑不同,由具体状态类实现
*/
void pass();
}
Turnstile:
class Turnstile {
// 转门的两个核心状态对象:锁定状态、未锁定状态(提前初始化,复用对象)
private TurnstileState lockedState;
private TurnstileState unlockedState;
// 转门当前的状态(初始值虽为lockedState,但构造方法中会重新初始化,后续main方法也会显式设置)
private TurnstileState state = lockedState;
/**
* 构造方法:初始化转门的两个状态对象,并关联当前转门实例
*/
public Turnstile() {
// 创建锁定状态对象,传入当前转门实例
lockedState = new LockedTurnstileState(this);
// 创建未锁定状态对象,传入当前转门实例
unlockedState = new UnLockedTurnstileState(this);
}
/**
* 获取锁定状态对象(供状态切换时使用)
* @return 锁定状态实例
*/
public TurnstileState getLockedState() {
return lockedState;
}
/**
* 获取未锁定状态对象(供状态切换时使用)
* @return 未锁定状态实例
*/
public TurnstileState getUnlockedState() {
return unlockedState;
}
/**
* 切换转门的当前状态
* @param state 新的状态对象
*/
public void setState(TurnstileState state) {
this.state = state;
}
/**
* 投币行为委托:将投币逻辑交给当前状态对象处理
*/
public void coin() {
state.coin();
}
/**
* 通行行为委托:将通行逻辑交给当前状态对象处理
*/
public void pass() {
state.pass();
}
/**
* 解锁动作:转门解锁时的具体行为(打印提示)
*/
public void unLock() {
System.out.println("turnstile unlock");
}
/**
* 锁定动作:转门锁定时的具体行为(打印提示)
*/
public void lock() {
System.out.println("turnstile lock");
}
/**
* 警报动作:转门被强行通过时的具体行为(打印提示)
*/
public void alarm() {
System.out.println("alarm");
}
/**
* 感谢提示动作:重复投币时的具体行为(打印提示,注意:原拼写错误"think you"已保留,如需修正可改为"thank you")
*/
public void thankYou() {
System.out.println("think you");
}
}
LockedTurnstileState(表示锁住的状态)
UnLockedTurnstileState (表示未锁的状态)
重点!!!
/**
* 锁定状态实现类:实现转门“锁定”状态下的投币、通行逻辑
*/
class LockedTurnstileState implements TurnstileState {
// 持有转门对象的引用,用于调用转门的方法(解锁、切换状态、触发警报等)
private Turnstile turnstile;
/**
* 构造方法:初始化时传入转门对象,建立状态与转门的关联
* @param turnstile 转门核心对象
*/
public LockedTurnstileState(Turnstile turnstile) {
this.turnstile = turnstile;
}
/**
* 锁定状态下投币:
* 1. 调用转门的解锁方法
* 2. 将转门状态切换为“未锁定”状态
*/
@Override
public void coin() {
turnstile.unLock(); // 执行解锁动作
turnstile.setState(turnstile.getUnlockedState()); // 切换状态
}
/**
* 锁定状态下通行:
* 转门处于锁定状态时有人强行通过,触发警报
*/
@Override
public void pass() {
turnstile.alarm(); // 执行警报动作
}
}
/**
* 未锁定状态实现类:实现转门“未锁定”状态下的投币、通行逻辑
*/
class UnLockedTurnstileState implements TurnstileState {
// 持有转门对象的引用,用于调用转门的方法(感谢提示、锁定、切换状态等)
private Turnstile turnstile;
/**
* 构造方法:初始化时传入转门对象,建立状态与转门的关联
* @param turnstile 转门核心对象
*/
public UnLockedTurnstileState(Turnstile turnstile) {
this.turnstile = turnstile;
}
/**
* 未锁定状态下投币:
* 转门已解锁时再次投币,仅触发“感谢”提示,不切换状态
*/
@Override
public void coin() {
turnstile.thankYou(); // 执行感谢提示动作
}
/**
* 未锁定状态下通行:
* 1. 调用转门的锁定方法
* 2. 将转门状态切换为“锁定”状态
*/
@Override
public void pass() {
turnstile.lock(); // 执行锁定动作(核心:原错误为unLock,已修正)
turnstile.setState(turnstile.getLockedState()); // 切换状态
}
}
/**
* 转门核心类:管理转门的状态,委托状态类处理具体行为
* 状态模式的上下文(Context):持有状态对象,提供状态切换和行为委托的能力
*/
二,题目练习
某大型商场内安装了多个简易的纸巾售卖机,自动出售2元钱一包的纸巾,且每次仅售出一包纸巾。纸巾售卖机的状态图如下图所示:
纸巾售卖机状态图
采用状态(State)模式来实现该纸巾售卖机,得到如下图所示的类图。其中类State为抽象类,定义了投币、退币、出纸巾等方法接口。类SoldState、SoldOutState、NoQuarterState和HasQuarterState分别对应图6-1中纸巾售卖机的4种状态:售出纸巾、纸巾售完、没有投币、有2元钱。
类 图
本题完整的代码结构如下:
abstract class State { protected TissueMachine tissueMachine; public void insertQuarter()//投币 { } public void ejectQuarter()//退币 { } public void turnCrank() //按下“出纸巾”按钮 { } public void dispense() //出纸巾 { } public abstract void printState(); } class TissueMachine { private State soldOutState, noQuarterState, hasQuarterState, soldState, state; private int count; //纸巾数 public TissueMachine(int numbers) { count = numbers; soldOutState = new SoldOutState(this); noQuarterState = new NoQuarterState(this); hasQuarterState = new HasQuarterState(this); soldState = new SoldState(this); state = noQuarterState; } public State getHasQuarterState() { return hasQuarterState; } public State getNoQuarterState() { return noQuarterState; } public State getSoldState() { return soldState; } public State getSoldOutState() { return soldOutState; } public int getCount() { return count; } public void setState(State state) { this.state = state; } public void printState() { this.state.printState(); } public void insertQuarter()//投币 { this.state.insertQuarter(); } public void ejectQuarter()//退币 { this.state.ejectQuarter(); } public void turnCrank() //按下“出纸巾”按钮 { this.state.turnCrank(); } public void dispense() //出纸巾 { this.state.dispense(); } }/**
此部分为本题缺失的代码,需要你完成并提交!
**/
public class Main { public static void main(String[] args) { TissueMachine tissueMachine = new TissueMachine(10); tissueMachine.printState(); tissueMachine.insertQuarter(); tissueMachine.printState(); tissueMachine.ejectQuarter(); tissueMachine.printState(); tissueMachine.insertQuarter(); tissueMachine.printState(); tissueMachine.turnCrank(); tissueMachine.printState(); tissueMachine.dispense(); tissueMachine.printState(); } }请完成缺失的代码并提交!
输入描述
无
输出描述
NoQuarterState
HasQuarterState
NoQuarterState
HasQuarterState
SoldState
NoQuarterState
答案
class HasQuarterState extends State {
private TissueMachine tissueMachine;
public HasQuarterState(TissueMachine tissueMachine){
this.tissueMachine=tissueMachine;
}
public void ejectQuarter()//退币
{
tissueMachine. setState(tissueMachine. getNoQuarterState());
}
public void turnCrank() //按下“出纸巾”按钮
{
tissueMachine. setState(tissueMachine. getSoldState());
}
public void printState(){
System.out.println("HasQuarterState");
}
}
class NoQuarterState extends State{
private TissueMachine tissueMachine;
public NoQuarterState(TissueMachine tissueMachine){
this.tissueMachine=tissueMachine;
}
public void insertQuarter()//投币
{
tissueMachine. setState(tissueMachine. getHasQuarterState());
}
public void printState(){
System.out.println("NoQuarterState");
}
}
class SoldState extends State{
private TissueMachine tissueMachine;
public SoldState(TissueMachine tissueMachine){
this.tissueMachine=tissueMachine;
}
public void dispense() //出纸巾
{
if(tissueMachine.getCount()>0)
{
tissueMachine. setState(tissueMachine. getNoQuarterState());
}
}
public void printState(){
System.out.println("SoldState");
}
}
class SoldOutState extends State{
private TissueMachine tissueMachine;
public SoldOutState(TissueMachine tissueMachine){
this.tissueMachine=tissueMachine;
}
public void printState(){
System.out.println("SoldOutState");
}
}
三,总结
- 当对象的行为随状态改变而变化时,考虑使用状态模式。
- 状态模式适用于替代复杂的条件或分支语句
设计模式系列持续更新,欢迎关注博主~
希望对大家有用,祝您开心~(o゜▽゜)o☆,有问题欢迎交流,俺会改的✊
更多推荐





所有评论(0)