设计模式之状态模式State Pattern详解Java版

一、定义

The State Pattern allows an object to alter its behavior
when its internal state changes. The object will appear to
change its class.
状态模式允许一个对象当它的内部状态改变时,改变它的行为。对象能够改变
它的类。

类图:
状态模式

二、实例

实现口香糖自动贩卖机的状态变化:
翻译:No Quarter(默认状态),insert quarter(投入硬币),Has Quarter(已经投币状态),eject quarter(退回硬币),turns crank(拉动摇杆),Gumball Sold(即将出口香糖状态),dispense gumball(出口香糖), gumballs(口香糖数量),Out of Gumballs(口香糖售罄状态)
自动贩卖机
(一)直观思路,编写一个状态机类,实现全部操作:

enum GumballState {
	NoQuarter,HasQuarter,GumballSold,OutOfGumballs
}

public class GumballMachine {
	private final static int DEFAULT_SIZE=10;
	private int gumballs;
	private GumballState state;
	
	public GumballMachine(int size) {
		gumballs=size;
		if(size<=0) {
			state=GumballState.OutOfGumballs;
		} else {
			state=GumballState.NoQuarter;
		}
	}
	
	public GumballMachine() {
		this(DEFAULT_SIZE);
	}
	
	public void insertQuarter() {
		if(state==GumballState.HasQuarter) {
			System.out.println("You cannot insert another quarter, you can choose to eject or turn crack");
		} else if(state==GumballState.GumballSold) {
			System.out.println("You cannot insert another quarter, you can only dispense Gumball");
		} else if(state==GumballState.OutOfGumballs) {
			System.out.println("Sorry, the machine is sold out");
		} else if(state==GumballState.NoQuarter) {
			state=GumballState.HasQuarter;
			System.out.println("You inserted a quarter!");
		}
	}
	
	public void ejectQuarter() {
		if(state==GumballState.GumballSold) {
			System.out.println("It cannot eject your quarter, you can only choose to dispense Gumball");
		} else if(state==GumballState.OutOfGumballs) {
			System.out.println("Sorry, the machine is sold out");
		} else if(state==GumballState.NoQuarter) {
			System.out.println("You didn't put a quarter");
		} else if(state==GumballState.HasQuarter) {
			state=GumballState.NoQuarter;
			System.out.println("The quarter will eject to you");
		}
	}
	
	public void turnCrank() {
		if(state==GumballState.GumballSold) {
			System.out.println("You cannot turn crack again, you can only choose to dispense Gumball");
		} else if(state==GumballState.OutOfGumballs) {
			System.out.println("Sorry, the machine is sold out");
		} else if(state==GumballState.NoQuarter) {
			System.out.println("You have to insert a quarter first");
		} else if(state==GumballState.HasQuarter) {
			state=GumballState.GumballSold;
			System.out.println("You turn crank");
		}
	}
	
	public void dispenseGumball() {
		if(state==GumballState.HasQuarter) {
			System.out.println("You have to turn crack first");
		} else if(state==GumballState.OutOfGumballs) {
			System.out.println("Sorry, the machine is sold out");
		} else if(state==GumballState.NoQuarter) {
			System.out.println("You have to insert a quarter first");
		} else if(state==GumballState.GumballSold) {
			gumballs--;
			System.out.println("The machine is to give you a gumball");
			if(gumballs>0) {
				state=GumballState.NoQuarter;
			} else {
				state=GumballState.OutOfGumballs;
			}
		}
		
	}

	@Override
	public String toString() {
		return "GumballMachine [gumballs=" + gumballs + ", state=" + state + "]\n";
	}
}

测试类:

public class Test {
	public static void main(String[] args) {
		GumballMachine gumballMachine = new GumballMachine(5);
		System.out.println(gumballMachine);
		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();
		gumballMachine.insertQuarter();
		gumballMachine.ejectQuarter();
		gumballMachine.turnCrank();
		gumballMachine.dispenseGumball();
		System.out.println(gumballMachine);
		
		gumballMachine.insertQuarter();
		gumballMachine.ejectQuarter();
		
		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();
		gumballMachine.dispenseGumball();
		System.out.println(gumballMachine);
		
		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();
		gumballMachine.dispenseGumball();
		System.out.println(gumballMachine);
		
		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();
		gumballMachine.dispenseGumball();
		System.out.println(gumballMachine);
		
		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();
		gumballMachine.dispenseGumball();
		System.out.println(gumballMachine);
		
		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();
		gumballMachine.dispenseGumball();
		System.out.println(gumballMachine);
	}
}

输出结果:

GumballMachine [gumballs=5, state=NoQuarter]

You inserted a quarter!
You turn crank
You cannot insert another quarter, you can only dispense Gumball
It cannot eject your quarter, you can only choose to dispense Gumball
You cannot turn crack again, you can only choose to dispense Gumball
The machine is to give you a gumball
GumballMachine [gumballs=4, state=NoQuarter]

You inserted a quarter!
The quarter will eject to you
You inserted a quarter!
You turn crank
The machine is to give you a gumball
GumballMachine [gumballs=3, state=NoQuarter]

You inserted a quarter!
You turn crank
The machine is to give you a gumball
GumballMachine [gumballs=2, state=NoQuarter]

You inserted a quarter!
You turn crank
The machine is to give you a gumball
GumballMachine [gumballs=1, state=NoQuarter]

You inserted a quarter!
You turn crank
The machine is to give you a gumball
GumballMachine [gumballs=0, state=OutOfGumballs]

Sorry, the machine is sold out
Sorry, the machine is sold out
Sorry, the machine is sold out
GumballMachine [gumballs=0, state=OutOfGumballs]

分析:这样写纯粹是面向实现编程,当需求改变,必然违背开闭原则。
(二)新的需求,要求10%概率出两颗糖

public interface State {
	void insertQuarter();
	
	void ejectQuarter();
	
	void turnCrank();
	
	void dispenseGumball();
}

class GumballMachine {
	private final static int DEFAULT_SIZE=10;
	private int gumballs;
	private State noQuarterState;
	private State hasQuarterState;
	private State soldOutState;
	private State soldState;
	private State winnerState;
	private State state;
	
	public GumballMachine(int size) {
		noQuarterState=new NoQuarterState(this);
		hasQuarterState=new HasQuarterState(this);
		soldOutState=new SoldOutState(this);
		soldState=new SoldState(this);
		winnerState=new WinnerState(this);
		gumballs=size;
		if(size>0) {
			state=noQuarterState;
		} else {
			state=soldOutState;
		}
	}
	
	public GumballMachine() {
		this(DEFAULT_SIZE);
	}

	public int getGumballs() {
		return gumballs;
	}

	public void setGumballs(int gumballs) {
		this.gumballs = gumballs;
	}
	
	public void insertQuarter() {
		state.insertQuarter();
	}
	
	public void ejectQuarter() {
		state.ejectQuarter();
	}
	
	public void turnCrank() {
		state.turnCrank();
		state.dispenseGumball();
	}
	
	public void setState(State state) {
		this.state=state;
	}

	public State getNoQuarterState() {
		return noQuarterState;
	}

	public State getHasQuarterState() {
		return hasQuarterState;
	}

	public State getSoldOutState() {
		return soldOutState;
	}

	public State getSoldState() {
		return soldState;
	}

	public State getWinnerState() {
		return winnerState;
	}
	
	public void releaseBall() {
		System.out.println("A gumball comes rolling out the slot...");
		if(gumballs!=0) {
			gumballs--;
		}
	}

	@Override
	public String toString() {
		return "GumballMachine [gumballs=" + gumballs + ", state=" + state + "]\n";
	}
	
}

class NoQuarterState implements State {
	private GumballMachine machine;

	public NoQuarterState(GumballMachine machine) {
		this.machine=machine;
	}

	@Override
	public void insertQuarter() {
		System.out.println("You inserted a quarter");
		machine.setState(machine.getHasQuarterState());
	}

	@Override
	public void ejectQuarter() {
		System.out.println("You haven't insert a quarter");
	}

	@Override
	public void turnCrank() {
		System.out.println("You haven't insert a quarter");
	}

	@Override
	public void dispenseGumball() {
		System.out.println("You haven't insert a quarter");
	}
	
}

class WinnerState implements State {
	private GumballMachine machine;
	
	public WinnerState(GumballMachine machine) {
		this.machine=machine;
	}
	
	@Override
	public void insertQuarter() {
		System.out.println("You can’t insert another quarter");
	}

	@Override
	public void ejectQuarter() {
		System.out.println("Sorry, you already turned the crank");
	}

	@Override
	public void turnCrank() {
		System.out.println("You have turned crank already!");
	}

	@Override
	public void dispenseGumball() {
		System.out.println("Congratulations! You are a WINNER, and you can get two gumballs!");
		machine.releaseBall();
		if(machine.getGumballs()==0) {
			System.out.println("Sold out!");
			machine.setState(machine.getSoldOutState());
		} else {
			machine.releaseBall();
			if(machine.getGumballs()==0) {
				machine.setState(machine.getSoldOutState());
			} else {
				machine.setState(machine.getNoQuarterState());
			}
		}
	}
	
}

class HasQuarterState implements State {
	private Random random =new Random();
	private GumballMachine machine;
	
	public HasQuarterState(GumballMachine machine) {
		this.machine=machine;
	}
	@Override
	public void insertQuarter() {
		System.out.println("You can’t insert another quarter");
	}

	@Override
	public void ejectQuarter() {
		System.out.println("Quarter returned!");
		machine.setState(machine.getNoQuarterState());
	}

	@Override
	public void turnCrank() {
		System.out.println("You turned...");
		int ran=random.nextInt(10);
		if(ran==0&&machine.getGumballs()>1) {
			machine.setState(machine.getWinnerState());
		} else {
			machine.setState(machine.getSoldState());
		}
	}

	@Override
	public void dispenseGumball() {
		System.out.println("No gumball dispensed");
	}
	
}

class SoldOutState implements State {
	private GumballMachine machine;
	
	public SoldOutState(GumballMachine machine) {
		this.machine=machine;
	}
	
	@Override
	public void insertQuarter() {
		System.out.println("The machine is sold out!");
	}

	@Override
	public void ejectQuarter() {
		System.out.println("The machine is sold out!");
	}

	@Override
	public void turnCrank() {
		System.out.println("The machine is sold out!");
	}

	@Override
	public void dispenseGumball() {
		System.out.println("The machine is sold out!");
	}
	
}

class SoldState implements State {
	private GumballMachine machine;
	
	public SoldState(GumballMachine machine) {
		this.machine=machine;
	}
	
	@Override
	public void insertQuarter() {
		System.out.println("You can’t insert another quarter");
	}

	@Override
	public void ejectQuarter() {
		System.out.println("Sorry, you already turned the crank");
	}

	@Override
	public void turnCrank() {
		System.out.println("You have turned crank already!");
	}

	@Override
	public void dispenseGumball() {
		machine.releaseBall();
		if(machine.getGumballs()==0) {
			System.out.println("Sold out!");
			machine.setState(machine.getSoldOutState());
		} else {
			machine.setState(machine.getNoQuarterState());
		}
	}
	
}

测试类:

public class Test {
	public static void main(String[] args) {
		GumballMachine gumballMachine = new GumballMachine(10);
		gumballMachine.insertQuarter();
		gumballMachine.ejectQuarter();
		System.out.println(gumballMachine);
		for(int i=0;i<10;i++) {
			gumballMachine.insertQuarter();
			gumballMachine.turnCrank();
			System.out.println(gumballMachine);
		}
	}
}

输出结果:

You inserted a quarter
Quarter returned!
GumballMachine [gumballs=10, state=chapter10.state.demo2.NoQuarterState@6d06d69c]

You inserted a quarter
You turned...
Congratulations! You are a WINNER, and you can get two gumballs!
A gumball comes rolling out the slot...
A gumball comes rolling out the slot...
GumballMachine [gumballs=8, state=chapter10.state.demo2.NoQuarterState@6d06d69c]

You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=7, state=chapter10.state.demo2.NoQuarterState@6d06d69c]

You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=6, state=chapter10.state.demo2.NoQuarterState@6d06d69c]

You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=5, state=chapter10.state.demo2.NoQuarterState@6d06d69c]

You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=4, state=chapter10.state.demo2.NoQuarterState@6d06d69c]

You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=3, state=chapter10.state.demo2.NoQuarterState@6d06d69c]

You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=2, state=chapter10.state.demo2.NoQuarterState@6d06d69c]

You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=1, state=chapter10.state.demo2.NoQuarterState@6d06d69c]

You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Sold out!
GumballMachine [gumballs=0, state=chapter10.state.demo2.SoldOutState@7852e922]

The machine is sold out!
The machine is sold out!
The machine is sold out!
GumballMachine [gumballs=0, state=chapter10.state.demo2.SoldOutState@7852e922]

类图:
状态模式

三、总结

状态模式很容易理解,它主要用来解决状态转换的问题,如进程的五种状态的转换,自动贩卖机的状态转换。UML中也有状态图,也可以用状态模式来解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

学无止境jl

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

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

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

打赏作者

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

抵扣说明:

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

余额充值