java 开发模式之十二 : 状态模式

本文详细介绍了状态模式的概念及其在糖果机项目中的应用。通过状态模式,一个对象可以根据内部状态的变化而改变其行为,使得对象看起来像是改变了类。文章还对比了传统实现与状态模式实现的区别,展示了如何使用状态模式更好地组织代码。

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

原理或定義

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式中的行为是由状态来决定的,不同的状态对应了不同的行

结构

环境类Context: 它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的Concrete State对象来处
抽象状态类State: 定义一个接口以封装与Context的一个特定状态相关的行为;
具体状态类ConcreteState: 每一子类实现一个与Context的一个状态相关的行为;

類圖

案例与代码

本模式使用一个糖果机项目来做示例

智能糖果机,用Java软件控制糖果机:
待机
投入一元硬币
转动把手
滑落一颗糖果
待机(根据机器内糖果库存情况,是否提示售罄)


传统实现:

public class CandyMachine {

	final static int SoldOutState = 0;
	final static int OnReadyState = 1;
	final static int HasCoin = 2;
	final static int SoldState = 3;

	private int state = SoldOutState;
	private int count = 0;

	public CandyMachine(int count) {
		this.count = count;
		if (count > 0) {
			state = OnReadyState;
		}
	}

	public void insertCoin() {
		switch (state) {
		case SoldOutState:
			System.out.println("you can't insert coin,the machine sold out!");
			break;
		case OnReadyState:
			state = HasCoin;
			System.out
					.println("you have inserted a coin,next,please turn crank!");
			break;
		case HasCoin:
			System.out.println("you can't insert another coin!");

			break;
		case SoldState:
			System.out.println("please wait!we are giving you a candy!");

			break;
		}

	}

	public void returnCoin() {
		switch (state) {
		case SoldOutState:
			System.out
					.println("you can't return,you haven't inserted a coin yet!");
			break;
		case OnReadyState:
			System.out.println("you haven't inserted a coin yet!");
			break;
		case HasCoin:

			System.out.println("coin return!");
			state = OnReadyState;

			break;
		case SoldState:
			System.out.println("sorry,you already have turned the crank!");

			break;
		}

	}

	public void turnCrank() {
		switch (state) {
		case SoldOutState:
			System.out.println("you turned,but there are no candies!");
			break;
		case OnReadyState:
			System.out.println("you turned,but you haven't inserted a coin!");
			break;
		case HasCoin:
			System.out.println("crank turn...!");
			state = SoldState;
			dispense();
			break;
		case SoldState:
			System.out
					.println("we are giving you a candy,turning another get nothing,!");
			break;
		}

	}

	private void dispense() {
		count = count - 1;
		System.out.println("a candy rolling out!");
		if (count > 0) {
			state = OnReadyState;
		} else {
			System.out.println("Oo,out of candies");
			state = SoldOutState;
		}

	}

	public void printstate() {

		switch (state) {
		case SoldOutState:
			System.out.println("***SoldOutState***");
			break;
		case OnReadyState:
			System.out.println("***OnReadyState***");
			break;
		case HasCoin:

			System.out.println("***HasCoin***");

			break;
		case SoldState:
			System.out.println("***SoldState***");
			break;
		}

	}
}
public class MainTest {
	public static void main(String[] args) {
		CandyMachine mCandyMachine=new CandyMachine(1);
		
		mCandyMachine.printstate();
		
		mCandyMachine.insertCoin();
		mCandyMachine.printstate();
		
		mCandyMachine.turnCrank();
		
		mCandyMachine.printstate();
		
		mCandyMachine.insertCoin();
		mCandyMachine.printstate();
		
		mCandyMachine.turnCrank();
		
		mCandyMachine.printstate();
	}
}

加入游戏元素:有10%的概率可以拿到2粒糖果。


以上的设计会违反开闭原则,并且对状态的维护麻烦。


开闭原则:对扩展开放,对修改原有的代码关闭。


状态模式的设计方案:


类图:


状态接口:

public interface State {
	public void insertCoin();
	public void returnCoin();
	public void turnCrank();
	public void dispense();
	public void printstate();
}


状态族类:

public class OnReadyState implements State {
	private CandyMachine mCandyMachine;
	public OnReadyState(CandyMachine mCandyMachine)
	{
		this.mCandyMachine=mCandyMachine;
	}

	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out
		.println("you have inserted a coin,next,please turn crank!");
		mCandyMachine.setState(mCandyMachine.mHasCoin);
	}

	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out.println("you haven't inserted a coin yet!");
		
	}

	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out.println("you turned,but you haven't inserted a coin!");
		
	}

	@Override
	public void dispense() {
		// TODO Auto-generated method stub

	}

	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***OnReadyState***");
		
	}

}
public class SoldOutState implements State {


	private CandyMachine mCandyMachine;
	public SoldOutState(CandyMachine mCandyMachine)
	{
		this.mCandyMachine=mCandyMachine;
	}


	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out.println("you can't insert coin,the machine sold out!");
		
	}


	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out
		.println("you can't return,you haven't inserted a coin yet!");


	}


	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out.println("you turned,but there are no candies!");
		
	}


	@Override
	public void dispense() {
		// TODO Auto-generated method stub


	}


	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***SoldOutState***");
	
	}


}
public class SoldState implements State {
	private CandyMachine mCandyMachine;
	public SoldState(CandyMachine mCandyMachine)
	{
		this.mCandyMachine=mCandyMachine;
	}


	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out.println("please wait!we are giving you a candy!");


	}


	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out.println("you haven't inserted a coin yet!");
		
	}


	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out
		.println("we are giving you a candy,turning another get nothing,!");


	}


	@Override
	public void dispense() {
		// TODO Auto-generated method stub
		
		mCandyMachine.releaseCandy();
		if (mCandyMachine.getCount() > 0) {
			mCandyMachine.setState(mCandyMachine.mOnReadyState);
		} else {
			System.out.println("Oo,out of candies");
			mCandyMachine.setState(mCandyMachine.mSoldOutState);
		}


	
	
	}


	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***SoldState***");
		
	}


}
public class WinnerState implements State {


	private CandyMachine mCandyMachine;


	public WinnerState(CandyMachine mCandyMachine) {
		this.mCandyMachine = mCandyMachine;
	}


	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out.println("please wait!we are giving you a candy!");


	}


	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out.println("you haven't inserted a coin yet!");


	}


	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out
				.println("we are giving you a candy,turning another get nothing,!");


	}


	@Override
	public void dispense() {
		// TODO Auto-generated method stub


		
		mCandyMachine.releaseCandy();
		if (mCandyMachine.getCount() == 0) {
			mCandyMachine.setState(mCandyMachine.mSoldOutState);
		} else {
			System.out.println("you are a winner!you get another candy!");
			mCandyMachine.releaseCandy();
			if (mCandyMachine.getCount() > 0) {
				mCandyMachine.setState(mCandyMachine.mOnReadyState);
			} else {
				System.out.println("Oo,out of candies");
				mCandyMachine.setState(mCandyMachine.mSoldOutState);
			}
		}


	}


	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***WinnerState***");


	}


}
public class HasCoin implements State {
	private CandyMachine mCandyMachine;


	public HasCoin(CandyMachine mCandyMachine) {
		this.mCandyMachine = mCandyMachine;
	}


	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out.println("you can't insert another coin!");


	}


	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out.println("coin return!");
		mCandyMachine.setState(mCandyMachine.mOnReadyState);
	}


	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out.println("crank turn...!");
		Random ranwinner=new Random();
		int winner=ranwinner.nextInt(10);
		if(winner==0)
		{
			mCandyMachine.setState(mCandyMachine.mWinnerState);


		}else
		{
			mCandyMachine.setState(mCandyMachine.mSoldState);


		}
		
	}


	@Override
	public void dispense() {
	}


	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***HasCoin***");


	}


}

糖果机类:

public class CandyMachine {

	State mSoldOutState;
	State mOnReadyState;
	State mHasCoin;
	State mSoldState;
	State mWinnerState;
	private State state;
	private int count = 0;

	public CandyMachine(int count) {
		this.count = count;
		mSoldOutState = new SoldOutState(this);
		mOnReadyState = new OnReadyState(this);
		mHasCoin = new HasCoin(this);
		mSoldState = new SoldState(this);
		mWinnerState = new WinnerState(this);
		if (count > 0) {
			state = mOnReadyState;
		} else {
			state = mSoldOutState;
		}
	}

	public void setState(State state) {
		this.state = state;
	}

	public void insertCoin() {
		state.insertCoin();
	}

	public void returnCoin() {
		state.returnCoin();
	}

	public void turnCrank() {
		state.turnCrank();
		state.dispense();
	}

	void releaseCandy() {

		// TODO Auto-generated method stub
		if (count > 0) {
			count = count - 1;
			System.out.println("a candy rolling out!");
		}

	}

	public int getCount() {
		return count;
	}

	public void printstate() {
		state.printstate();
	}
}
public class MainTest {
	public static void main(String[] args) {
		CandyMachine mCandyMachine = new CandyMachine(6);


		mCandyMachine.printstate();


		mCandyMachine.insertCoin();
		mCandyMachine.printstate();


		mCandyMachine.turnCrank();


		mCandyMachine.printstate();


		mCandyMachine.insertCoin();
		mCandyMachine.printstate();


		mCandyMachine.turnCrank();


		mCandyMachine.printstate();
	}
}

状态模式:能根据内部状态的变化,改变对象的行为,看起来好像修改了类。不同的状态对应不同的类文件,增加了系统文件个数。


使用場景

1. 一个对象的行为取决于他的状态,并且它必须在运行时根据状态改变它的行为;
2.一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状

優缺點

主要优点有:

1.状态模式将不同状态所对应的行为彼此分隔开来,降低程序的耦合,从而在新增或修改状态时,可以避免程序互相影响。

2.状态模式将状态的逻辑处理变化交由上下文对象Context管理,便于客户端的调用

 

缺点主要有

不同的状态对应不同的类文件,增加了系统文件个数,不便于维护管理

### 订单状态图的设计与实现 订单状态图是一种用于描述订单在系统中各个状态及其转换规则的工具。通过 UML 状态图,可以清晰地表示订单的不同状态以及这些状态之间的迁移路径。 #### 1. **订单状态图的核心概念** 订单状态图基于UML状态图的概念构建,其中核心要素包括状态、事件和转移[^1]。 - **状态**:订单的状态是指其当前所处的具体情况,例如“待支付”、“已付款”、“配送中”等。每个状态都具有一定的生命周期,并且在此期间可能会执行特定的动作或等待某些事件的发生[^4]。 - **事件**:事件是触发状态变化的原因,例如用户完成支付操作会触发“待支付→已付款”的状态转变。 - **转移**:转移是从一个状态迁移到另一个状态的过程,通常伴随着某种条件判断和动作执行。 #### 2. **订单状态图的设计要点** 设计订单状态图时需注意以下几点: - **状态值的有限性和完备性**:确保所有可能的状态都被覆盖,且各状态之间互斥,不会产生歧义[^2]。 - **子状态的支持**:如果某一状态较为复杂,可进一步细分为多个子状态。例如,“已取消”这一状态可以划分为“客户取消”、“商家取消”和“系统取消”。 - **瞬时态的避免**:应避免定义过于短暂的状态,因为这类状态难以维护并可能导致逻辑混乱。例如,“评价中”这种短时间存在的状态不如将其归入“已完成”状态更为合理。 #### 3. **订单状态图的示例** 以下是订单状态图的一个简单示例: ```plaintext +-------------------+ | 待支付 | +-------------------+ ↓ (支付成功) +-------------------+ | 已付款 | +-------------------+ ↓ (确认发货) +-------------------+ | 配送中 | +-------------------+ ↓ (签收完成) +-------------------+ | 已完成 | +-------------------+ ``` 此图为线性的状态流转过程,实际应用中可根据需求增加更多分支和异常处理逻辑。例如引入“退款申请”、“退货申请”等特殊流程。 #### 4. **Java中的订单状态机实现示例** 以下是一个简单的订单状态机实现代码片段,展示了如何利用 Java 枚举来管理订单状态及状态间的转换: ```java public enum OrderStatus { PENDING_PAYMENT, PAID, SHIPPED, DELIVERED; public boolean canTransitionTo(OrderStatus target) { switch (this) { case PENDING_PAYMENT: return target == PAID; case PAID: return target == SHIPPED; case SHIPPED: return target == DELIVERED; default: return false; } } public void transitionTo(OrderStatus target) throws IllegalStateException { if (!canTransitionTo(target)) { throw new IllegalStateException("Invalid state transition from " + this.name() + " to " + target.name()); } System.out.println(this.name() + " -> " + target.name()); } } // 测试代码 OrderStatus current = OrderStatus.PENDING_PAYMENT; current.transitionTo(OrderStatus.PAID); // 输出: PENDING_PAYMENT -> PAID current = OrderStatus.SHIPPED; current.transitionTo(OrderStatus.DELIVERED); // 输出: SHIPPED -> DELIVERED ``` 上述代码实现了基本的状态验证机制,防止非法状态跳转发生。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值