状态模式

状态模式是一种设计模式,用于处理对象在不同状态间转换时的行为。它将每个状态封装为独立的类,当对象状态改变时,其行为也随之改变,避免了大量条件分支语句。本文通过"普通"和"状态切换"两个案例详细阐述了状态模式的应用,并列举了其优点和适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

状态模式:主要用来解决对象在多种状态转换时需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换。当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像改变了其类。

举例:人的一生。小的时候(假设是0~7岁)只能当幼儿园学生;青年时(假设是7 ~ 18岁)可以当初中和高中生,相应可以做的事情也变多了;成年时,可以做大学生,硕士生等等,做的事情变得更多了。

  • 状态模式的关键是将对象的状态封装称为独立的类,对象调用方法时,可以委托当前对象所具有的状态调用相应的方法,是当前对象看起来好像是修改了它的类。

角色说明:

  • 环境( Context ):环境是一个类,该类含有抽象状态声明的变量,可以引用任何具体状态类的实例。用户对该环境类的实例在某种状态下的行为感兴趣。
  • 抽象状态( State ):抽象状态是一个接口或抽象类。抽象状态中定义了与环境的一个特定状态相关的若干个方法。
  • 具体状态( Concrete State ):具体状态是实现( 扩展 )抽象状态( 抽象类 )的类。
“普通” 状态模式案例

Thermometer.java

public class Thermometer { // 环境
	TemperatureState state;
	public void showMessage() {
		System.out.println("*********");
		state.showTemperature();
		System.out.println("*********");
	}
	
	public void setState(TemperatureState state) {
		this.state = state;
	}
}

TemperatureState.java

public interface TemperatureState { // 抽象状态
	public void showTemperature();
}

LowState.java

public class LowState implements TemperatureState{ // 具体状态
	double n = 0;
	public LowState(double n) {
		if(n<=0) {
			this.n=n;
		}
	}
	@Override
	public void showTemperature() {
		System.out.println("现在的温度是"+n+"属于低温度");
	}
}

MiddleState.java

public class MiddleState implements TemperatureState{ // 具体状态
	double n = 15;
	public MiddleState(double n) {
		if(n>0&&n<26) {
			this.n=n;
		}
	}
	
	@Override
	public void showTemperature() {
		System.out.println("现在的温度是"+n+"属于低温度");
	}
}

HeightState.java

public class HeightState implements TemperatureState{ // 具体状态
	double n = 15;
	public HeightState(double n) {
		if(n>=39) {
			this.n=n;
		}
	}
	
	@Override
	public void showTemperature() {
		System.out.println("现在的温度是"+n+"属于低温度");
	}
}

Application4.java

public class Application4 {
	public static void main(String[] args) {
		Thermometer thermometer = new Thermometer();
		thermometer.setState(new LowState(0));
		thermometer.showMessage();
		
		thermometer.setState(new MiddleState(15.0));
		thermometer.showMessage();
		
		thermometer.setState(new HeightState(40.0));
		thermometer.showMessage();
	}
}

运行结果:
在这里插入图片描述
结果将所有的状态变化的行为都展示了出来。

“状态切换”状态模式案例

Activity.java

public class Activity { // 环境, 这个例子属于 "状态切换" ,对应到课本上是p205页, 不是普通的状态模式
	/**
	 * 与普通的状态模式相比,这个 "状态切换" 就是把状态切换的操作放在了程序内部实现,不用显示的展现给用户实现;
	 * 也就是说普通的状态模式会把切换状态的操作的过程和结果都展现出来给用户,这样是不符合生活实际的,体验感会及其差劲。
	 *  
	 * */
	State state = null; // 活动当前状态, 是可以变化的
	int count = 0; // 奖品数量
	
	// 四个属性表示四种状态
	State noRaffleState = new NoRaffleState(this);
	State canRaffleState = new CanRaffleState(this);
	State dispenseOutState = new DispenseOutState(this);
	State dispenseState = new DispenseState(this);
	
	// 初始化当前状态
	public Activity(int count) {
		this.state = getNoRaffleState(); // 初始化的状态是 不能抽奖状态
		this.count = count;
	}
	
	// 扣分(执行每个状态的扣分政策)
	public void deduceMoney() {
		state.deduceMoney();
	}
	
	// 抽奖
	public void raffle() {
		if(state.raffle()) { // 满足条件就是抽奖成功
			state.dispensePrize(); // 领取奖品
		}
	}
	
	public State getState() {
		return state;
	}
	
	public void setState(State state) {
		this.state = state;
	}
	
	public void setCount(int count) {
		this.count = count;
	}
	
	public int getCount() {
		int curCount = count;
		count--; // 每领取一次奖品, 奖品数量减少一个
		return curCount;
	}

	public State getNoRaffleState() {
		return noRaffleState;
	}

	public void setNoRaffleState(State noRaffleState) {
		this.noRaffleState = noRaffleState;
	}

	public State getCanRaffleState() {
		return canRaffleState;
	}

	public void setCanRaffleState(State canRaffleState) {
		this.canRaffleState = canRaffleState;
	}

	public State getDispenseOutState() {
		return dispenseOutState;
	}

	public void setDispenseOutState(State dispenseOutState) {
		this.dispenseOutState = dispenseOutState;
	}

	public State getDispenseState() {
		return dispenseState;
	}

	public void setDispenseState(State dispenseState) {
		this.dispenseState = dispenseState;
	}
}

State.java

public interface State { // 抽象状态
	public void deduceMoney(); // 扣除50积分 
	public boolean raffle(); // 是否抽中奖品
	public void dispensePrize(); // 发放奖品
}

NoRaffleState.java

public class NoRaffleState implements State{ // 具体状态(不能抽奖状态), 当前状态可以扣除积分, 扣除后将状态设置为可以抽奖状态, 也就是当前状态不可以抽奖
	//状态和行为是一一对应的,状态之间可以相互转换
	Activity activity;
	
	public NoRaffleState(Activity activity) {
		this.activity=activity;
	}
	
	@Override
	public void deduceMoney() {
		System.out.println("扣除50积分成功,可以抽奖了");
		activity.setState(activity.getCanRaffleState());
	}

	@Override
	public boolean raffle() {
		System.out.println("扣除积分之后才可以抽奖哦");
		return false;
	}

	@Override
	public void dispensePrize() {
		System.out.println("不能发放奖品");
	}
}

CanRaffleState.java

public class CanRaffleState implements State{ // 具体状态(可以抽奖状态), 当前状态不可以扣分
	Activity activity;
	
	public CanRaffleState(Activity activity) {
		this.activity=activity;
	}
	
	@Override
	public void deduceMoney() {
		System.out.println("以及扣除过积分了");
	}

	@Override
	public boolean raffle() {
		System.out.println("正在抽奖,请稍等");
		Random random = new Random();
		int num = random.nextInt(11); // nextInt(int index)  返回伪随机的,均匀分布的, int值介于0(含)和指定值(不包括),从该随机数生成器的序列绘制
		//10%中奖机会
		if(num==0) {
			activity.setState(activity.getDispenseState());
			return true;
		}else { // 90%未中奖机会
			System.out.println("很遗憾没有抽中奖品");
			activity.setState(activity.getNoRaffleState()); // 改变状态为不能抽奖
			return false;
		}
	}

	@Override
	public void dispensePrize() {
		System.out.println("未中奖, 不能发放奖品");
	}
}

DispenseState.java

public class DispenseState implements State{ // 具体状态(发放奖品的状态)
	Activity activity;
	
	public DispenseState(Activity activity) {
		this.activity=activity;
	}
	
	@Override
	public void deduceMoney() {
		System.out.println("不能扣除积分");
	}

	@Override
	public boolean raffle() {
		System.out.println("不能抽奖");
		return false;
	}

	@Override
	public void dispensePrize() {
		if(activity.getCount()>0) {
			System.out.println("恭喜中奖了");
			activity.setState(activity.getNoRaffleState()); // 改变状态为不能抽奖
		}else {
			System.out.println("奖品发放完了");
//			activity.setState(activity.getDispenseOutState()); // 改变状态为奖品发送完毕, 后面我们不能抽奖了
			System.exit(0); // 上一句代码可以替换为此,如果是这种方式,那么当没有奖品时就会直接退出系统不会执行之后没有意义(没有奖品)的抽奖活动
		}
	}
}

DispenseOutState.java

public class DispenseOutState implements State{ // 具体状态(奖品发放完毕状态), 此后抽奖活动结束了
	Activity activity;
	
	public DispenseOutState(Activity activity) {
		this.activity=activity;
	}
	
	// 这个状态里面没有在对 State 进行任何的改变,所以一旦变为此状态就不会再变成其它状态,所以当奖品发放完时本就是本次抽奖活动结束,也就是此状态
	@Override
	public void deduceMoney() {
		System.out.println("奖品发送完了, 请下次再参加");
	}

	@Override
	public boolean raffle() {
		System.out.println("奖品发送完了, 请下次再参加"); 
		return false;
	}

	@Override
	public void dispensePrize() {
		System.out.println("奖品发送完了, 请下次再参加");
	}
}

Application2.java

public class Application2 {
	public static void main(String[] args) {
		Activity activity = new Activity(1); // 创建活动对象,奖品池有一个奖品
		
		//连续抽奖300次
		for(int i=0;i<30;i++) {
			System.out.println("--------第"+(i+1)+"次抽奖--------");
			//参将抽奖, 第一步点击扣除积分
			activity.deduceMoney();
			//第二步抽奖
			activity.raffle();
		}
	}
}

运行结果:
在这里插入图片描述

“状态切换” 与 “普通” 的状态模式相比,“切换” 就是把 “切换” 放在了类的内部,不用用户显示的实现。

状态切换解释说明:环境实例在某种状态下执行一个方法后,可能导致该实例的状态发生变化。程序通过使用状态模式可方便地将环境实例从一个状态切换为另一个状态。当一个环境实例有确定的若干个状态时,可以由环境实例本身负责状态的切换,该环境实例可以含有所有状态的引用,并提供设置改变状态的方法,比如setState(State state)方法。

状态模式优点:
  • 代码有很强的可读性。
  • 方便维护(删除容易产生问题的if-else语句)。
  • 使用一个类封装对象的一种状态,很容易动态的增加新的状态。
  • 在状态模式下。环境(context)中不必出现大量的条件判断语句。环境(context)实例所呈现的状态变得更加清晰,容易理解。
  • 可以让用户程序很方便地切换环境(context)实例的状态
  • 不会让环境(context)的实例中出现内部状态不一致的情况。
  • 当状态对象没有实例变量时,环境(context)的各个实例可以共享一个状态对象。
适合场景:
  • 一个对象的行为依赖于它的状态,并且它必须在运行时根据状态改变它的行为。
  • 需要编写大量的条件分支语句来决定一个操作的行为,而且这些条件恰好表示对象的一种状态。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝朋友丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值