状态模式:
允许对象在内部状态改变时改变它的行为,对象看起来好想修改了它的类。
问题简单描述:
需要实现一个糖果自动售货机。原先的售货机状态转化如下:
后需求变动添加了10%概率双倍糖果的赢家状态,状态转化如下:
原先的静态状态量表示状态,大段if else代码完成状态转化难以扩展代码需要重构。
解决思路:
创建状态接口,包含所有引起状态改变的事件处理的方法,将每种状态单独封装成类,继承状态接口,分别实现每种事件的处理方法。
UML图:
实现代码:
state接口
package state;
public abstract class State {
/**
* 投入硬币
*/
public void insertQuarter(){
System.out.println("please wait,we will give you a gumball soon");
}
/**
* 退币
*/
public void ejectQuarter(){
System.out.println("can't eject quarter");
}
/**
* 转动曲柄
*/
public void turnCrank(){
System.out.println("sorry,you have turned the crank");
}
/**
* 发糖
*/
public void dispense(){
System.out.println("you have to insert quarter");
}
}
具体state类
package state;
/**
* 无硬币状态
* @author terry
*
*/
public class NoQuarterState extends State {
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
/**
* 重写塞入硬币方法,塞入硬币后进入有硬币状态
*/
public void insertQuarter(){
System.out.println("insert quarter");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
public void turnCrank(){
System.out.println("you have to insert quarter");
}
}
package state;
import java.util.Random;
/**
* 有硬币状态
* @author terry
*
*/
public class HasQuarterState extends State{
GumballMachine gumballMachine;
Random randomWinner=new Random(System.currentTimeMillis());
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
/**
* 重写转动曲柄,机器进去售卖状态或胜者状态
*/
public void turnCrank(){
System.out.println("you turned……");
int winner = randomWinner.nextInt(10);
if(winner==0&&(gumballMachine.getCount()>1)){
gumballMachine.setState(gumballMachine.getWinnerState());
}else{
gumballMachine.setState(gumballMachine.getSoldState());
}
}
/**
* 重写退回硬币,硬币退回,机器回到无硬币状态
*/
public void ejectQuarter(){
System.out.println("eject quarter");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
}
package state;
/**
* 销售状态
* @author terry
*
*/
public class SoldState extends State {
GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
/**
* 重写发糖方法,机器发糖,发完糖如果还有糖变成无硬币状态,否则变成售完状态
*/
public void dispense(){
gumballMachine.releaseBall();
if(gumballMachine.getCount()>0){
gumballMachine.setState(gumballMachine.getNoQuarterState());
}else{
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
package state;
/**
* 售罄状态
* @author terry
*
*/
public class SoldOutState extends State{
GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
/**
* 重写塞硬币状态
*/
public void insertQuarter(){
System.out.println("sold out! eject quarter");
}
public void turnCrank(){
System.out.println("sold out! please wait");
}
}
package state;
/**
* 获胜状态
*
* @author terry
*
*/
public class WinnerState extends State {
GumballMachine gumballMachine;
public WinnerState(GumballMachine gumballMachine) {
super();
this.gumballMachine = gumballMachine;
}
/**
* 重写发糖方法,机器发两颗糖,发完糖如果还有糖变成无硬币状态,否则变成售完状态
*/
public void dispense() {
System.out.println("conguratulation ! you are a winner!");
gumballMachine.releaseBall();
if (gumballMachine.getCount() > 0) {
gumballMachine.releaseBall();
if (gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
gumballMachine.setState(gumballMachine.getSoldOutState());
}
} else {
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
售货机类(Context)
package state;
/**
* 糖果机
* @author terry
*
*/
public class GumballMachine {
NoQuarterState noQuarterState;
HasQuarterState hasQuarterState;
SoldState soldState;
SoldOutState soldOutState;
WinnerState winnerState;
State state;
int count=0;
/**
* 初始化时添加糖果
* @param count
*/
public GumballMachine(int count) {
noQuarterState=new NoQuarterState(this);
hasQuarterState=new HasQuarterState(this);
soldState=new SoldState(this);
soldOutState=new SoldOutState(this);
winnerState=new WinnerState(this);
this.count = count;
if(count>0){
state=noQuarterState;
}else{
state=soldOutState;
}
}
/**
* 机器出糖果
*/
public void releaseBall(){
if(count>0){
count--;
System.out.println("A gumball comes rolling out the slot……");
}
}
/**
* 投入硬币
*/
public void insertQuarter(){
state.insertQuarter();
}
/**
* 退币
*/
public void ejectQuarter(){
state.ejectQuarter();
}
/**
* 转动曲柄
*/
public void turnCrank(){
state.turnCrank();
if(count>0){
state.dispense();
}
}
public NoQuarterState getNoQuarterState() {
return noQuarterState;
}
public void setNoQuarterState(NoQuarterState noQuarterState) {
this.noQuarterState = noQuarterState;
}
public HasQuarterState getHasQuarterState() {
return hasQuarterState;
}
public void setHasQuarterState(HasQuarterState hasQuarterState) {
this.hasQuarterState = hasQuarterState;
}
public SoldState getSoldState() {
return soldState;
}
public void setSoldState(SoldState soldState) {
this.soldState = soldState;
}
public SoldOutState getSoldOutState() {
return soldOutState;
}
public void setSoldOutState(SoldOutState soldOutState) {
this.soldOutState = soldOutState;
}
public WinnerState getWinnerState() {
return winnerState;
}
public void setWinnerState(WinnerState winnerState) {
this.winnerState = winnerState;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
测试类:
package state;
public class Test {
public static void main(String[] args) {
GumballMachine gumballMachine=new GumballMachine(3);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("========================================");
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
System.out.println("========================================");
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("========================================");
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("========================================");
}
}
运行结果:
状态模式将不同的状态用不同的类表示,并组合进context中,context将行为委托给当前的状态对象,实现一个对象基于内部状态拥有不同行为。增加了类的数目但是使得可扩展性大大增强。
^ ^欢迎批评指正