转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/26350617
状态模式给了我眼前一亮的感觉啊,值得学习~
先看定义:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。
下面使用个例子来说明状态模式的用法,现在有个自动售货机的代码需要我们来写,状态图如下:

分析一个这个状态图:
a、包含4个状态(我们使用4个int型常量来表示)
b、包含3个暴露在外的方法(投币、退币、转动手柄)
c、我们需要处理每个状态下,用户都可以触发这三个动作。
下面我们根据分析的结果,写出代码:
package com.zhy.pattern.status;
/**
* 自动售货机
*
* @author zhy
*
*/
public class VendingMachine
{
/**
* 已投币
*/
private final static int HAS_MONEY = 0;
/**
* 未投币
*/
private final static int NO_MONEY = 1;
/**
* 售出商品
*/
private final static int SOLD = 2;
/**
* 商品售罄
*/
private final static int SOLD_OUT = 3;
private int currentStatus = NO_MONEY;
/**
* 商品数量
*/
private int count = 0;
public VendingMachine(int count)
{
this.count = count;
if (count > 0)
{
currentStatus = NO_MONEY;
}
}
/**
* 投入硬币,任何状态用户都可能投币
*/
public void insertMoney()
{
switch (currentStatus)
{
case NO_MONEY:
currentStatus = HAS_MONEY;
System.out.println("成功投入硬币");
break;
case HAS_MONEY:
System.out.println("已经有硬币,无需投币");
break;
case SOLD:
System.out.println("请稍等...");
break;
case SOLD_OUT:
System.out.println("商品已经售罄,请勿投币");
break;
}
}
/**
* 退币,任何状态用户都可能退币
*/
public void backMoney()
{
switch (currentStatus)
{
case NO_MONEY:
System.out.println("您未投入硬币");
break;
case HAS_MONEY:
currentStatus = NO_MONEY;
System.out.println("退币成功");
break;
case SOLD:
System.out.println("您已经买了糖果...");
break;
case SOLD_OUT:
System.out.println("您未投币...");
break;
}
}
/**
* 转动手柄购买,任何状态用户都可能转动手柄
*/
public void turnCrank()
{
switch (currentStatus)
{
case NO_MONEY:
System.out.println("请先投入硬币");
break;
case HAS_MONEY:
System.out.println("正在出商品....");
currentStatus = SOLD;
dispense();
break;
case SOLD:
System.out.println("连续转动也没用...");
break;
case SOLD_OUT:
System.out.println("商品已经售罄");
break;
}
}
/**
* 发放商品
*/
private void dispense()
{
switch (currentStatus)
{
case NO_MONEY:
case HAS_MONEY:
case SOLD_OUT:
throw new IllegalStateException("非法的状态...");
case SOLD:
count--;
System.out.println("发出商品...");
if (count == 0)
{
System.out.println("商品售罄");
currentStatus = SOLD_OUT;
} else
{
currentStatus = NO_MONEY;
}
break;
}
}
}
针对用户的每个动作,我们考虑了在任何状态下发生,并做了一定处理。下面进行一些测试:
package com.zhy.pattern.status;
public class TestTra
{
public static void main(String[] args)
{
VendingMachine machine = new VendingMachine(10);
machine.insertMoney();
machine.backMoney();
System.out.println("-----------");
machine.insertMoney();
machine.turnCrank();
System.out.println("----------压力测试-----");
machine.insertMoney();
machine.insertMoney();
machine.turnCrank();
machine.turnCrank();
machine.backMoney();
machine.turnCrank();
}
}
输出结果:
成功投入硬币 退币成功 ----------- 成功投入硬币 正在出商品.... 发出商品... ----------压力测试----- 成功投入硬币 已经有硬币,无需投币 正在出商品.... 发出商品... 请先投入硬币 您未投入硬币 请先投入硬币感觉还是不错的,基本实现了功能,但是有些事情是不可避免的,那就是需求的变化,现在为了提升销量,当用户每次转动手柄买商品的时候,有10%的几率赠送一瓶。
现在的状态图