State模式也叫状态模式,是行为设计模式的一种。State模式允许通过改变对象的内部状态而改变对象的行为,这个对象表现得就好像修改了它的类一样。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转译到表现不同状态的一系列类当中,可以把复杂的判断逻辑简化。
糖果公司想要设计一个糖果机器,现在需要我们上场啦。
不加思索地,我们就有了第一个方案。
类 | Candymachine | - | - | - |
---|---|---|---|---|
域(表示糖果机的四个状态) | Sold_out | No_quarter | Has_quarter | Slod |
方法(四个方法,分别对应不同状态下的反应) | insertQuarter() | ejectQuarter() | turnCrank() | dispense() |
接下来就是实现简单的糖果机器了。
// An highlighted block
package design.state.gys.nostate;
public class Candymachine {
final static int Sold_out=0;
final static int No_quarter=1;
final static int Has_quarter=2;
final static int Sold=3;
int state=Sold_out;
int count=0;
public Candymachine(int count) {
super();
this.count = count;
if(this.count>0)
this.state=No_quarter;
}
public void insertQuarter() {
if(state==Sold_out)
System.out.println("全部售出,无法放入硬币");
else if(state==No_quarter) {
System.out.println("投入硬币");
state=Has_quarter;
}
else if(state==Has_quarter)
System.out.println("已投入硬币,转动摇杆吧");
else if(state==Sold)
System.out.println("正在出售糖果,稍后...");
}
public void ejectQuarter() {
if(state==Sold_out)
System.out.println("全部售出,无法购买");
else if(state==No_quarter)
System.out.println("请投入硬币");
else if(state==Has_quarter) {
System.out.println("已退出硬币");
state=No_quarter;
}
else if(state==Sold)
System.out.println("正在出售糖果,无法退币");
}
public void turnCrank() {
if(state==Sold_out)
System.out.println("全部售出,无法购买");
else if(state==No_quarter)
System.out.println("请投入硬币");
else if(state==Has_quarter) {
System.out.println("已投入硬币,转动摇杆吧");
state=Sold;
dispense();
}
else if(state==Sold)
System.out.println("已掉落糖果,无法再次掉落");
}
public void dispense() {
if(state==Sold) {
System.out.println("糖果掉落");
count--;
if(count==0)
state=Sold_out;
else
state=No_quarter;
}
else if (state==No_quarter) {
System.out.println("请投入硬币");
}else if(state==Sold_out) {
System.out.println("全部售出,无法购买");
}else {
System.out.println("请先转动摇杆");
}
}
}
大量的slse if语句充斥着代码,先不管这些,来看看是否能运行吧。
// An highlighted block
package design.state.gys.nostate;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Candymachine cm=new Candymachine(5);
cm.turnCrank();
cm.insertQuarter();
cm.ejectQuarter();
cm.insertQuarter();
cm.turnCrank();
cm.turnCrank();
cm.ejectQuarter();
}
}
屏住呼吸,看看验收情况:
// An highlighted block
请投入硬币
投入硬币
已退出硬币
投入硬币
已投入硬币,转动摇杆吧
糖果掉落
请投入硬币
请投入硬币
糖果公司的老板还算满意,但是她希望我们能够设计出更好一些的糖果机器,便于扩展接入。
现在,我们为机器的每一个状态都定义一个类,用于封装每个动作下的反应,当动作发生时,委托给现在的状态进行处理。
首先我们定义一个状态接口。
// An highlighted block
package design.state.gys.state;
public interface State {
void insertQuuarter();
void ejectQuarter();
void turnCrack();
void dispense();
}
接下来就是定义我们所需要的四个状态,这些类将负责在对应状态下的动作执行,并且在每个状态的构造器内传入糖果机器以便获取状态:
Sold:
// An highlighted block
package design.state.gys.state;
public class Sold implements State{
CandyMachine cm;
public Sold(CandyMachine cm) {
super();
this.cm = cm;
}
@Override
public void insertQuuarter() {
// TODO Auto-generated method stub
System.out.println("请稍等,正在掉落糖果");
}
@Override
public void ejectQuarter() {
// TODO Auto-generated method stub
System.out.println("正在掉落糖果,无法退币");
}
@Override
public void turnCrack() {
// TODO Auto-generated method stub
System.out.println("已经转动摇杆,无法再转");
}
@Override
public void dispense() {
// TODO Auto-generated method stub
cm.releaseBall();
if(cm.count>0)
cm.setState(cm.getNoquarter());
else {
System.out.println("全部售完");
cm.setState(cm.getSoleout());
}
}
}
Soldout:
// An highlighted block
package design.state.gys.state;
public class Soldout implements State{
CandyMachine cm;
public Soldout(CandyMachine cm) {
super();
this.cm = cm;
}
@Override
public void insertQuuarter() {
// TODO Auto-generated method stub
System.out.println("已售完,无法投币");
}
@Override
public void ejectQuarter() {
// TODO Auto-generated method stub
System.out.println("未投币,无法退币");
}
@Override
public void turnCrack() {
// TODO Auto-generated method stub
System.out.println("已售完");
}
@Override
public void dispense() {
// TODO Auto-generated method stub
System.out.println("已售完");
}
}
HasQuatrer:
// An highlighted block
package design.state.gys.state;
public class HasQuarter implements State{
CandyMachine cm;
public HasQuarter(CandyMachine cm) {
super();
this.cm = cm;
}
@Override
public void insertQuuarter() {
// TODO Auto-generated method stub
System.out.println("已经投入硬币,转动摇杆吧");
}
@Override
public void ejectQuarter() {
// TODO Auto-generated method stub
System.out.println("正在退币");
cm.setState(cm.getNoquarter());
}
@Override
public void turnCrack() {
// TODO Auto-generated method stub
System.out.println("转动摇杆,请稍后");
cm.setState(cm.getSold());
}
@Override
public void dispense() {
// TODO Auto-generated method stub
System.out.println("转动摇杆吧");
}
}
NoQuarter:
// An highlighted block
package design.state.gys.state;
public class NoQuarter implements State{
CandyMachine cm;
public NoQuarter(CandyMachine cm) {
super();
this.cm = cm;
}
@Override
public void insertQuuarter() {
// TODO Auto-generated method stub
System.out.println("投入硬币");
cm.setState(cm.getHasquarter());
}
@Override
public void ejectQuarter() {
// TODO Auto-generated method stub
System.out.println("未投入硬币,无法退币");
}
@Override
public void turnCrack() {
// TODO Auto-generated method stub
System.out.println("未投入硬币,无法摇动摇杆");
}
@Override
public void dispense() {
// TODO Auto-generated method stub
System.out.println("请投入硬币");
}
}
状态类定义完成,接下来事糖果机的设计了:
// An highlighted block
package design.state.gys.state;
public class CandyMachine {
State sold;
State noquarter;
State hasquarter;
State soleout;
State state=null;
int count =0;
public CandyMachine(int count) {
super();
this.count = count;
sold=new Sold(this);
noquarter=new NoQuarter(this);
hasquarter=new HasQuarter(this);
soleout=new Sold(this);
if(count>0)
state=noquarter;
}
public void insertQuuarter() {
state.insertQuuarter();
}
public void ejectQuarter() {
state.ejectQuarter();
}
public void turnCrack() {
state.turnCrack();
if(state==sold)
state.dispense();
}
void setState(State state) {
this.state=state;
}
void releaseBall() {
System.out.println("掉落糖果");
if(count!=0)
count--;
}
public State getSold() {
return sold;
}
public State getNoquarter() {
return noquarter;
}
public State getHasquarter() {
return hasquarter;
}
public State getSoleout() {
return soleout;
}
public int getCount() {
return count;
}
}
貌似比上次的设计轻松多了,并且我们增加了其他的功能,可以查询糖果机的状态、设置状态等,并且更加容易进行扩展状态,只需要实现State接口,并将状态加入就,行。
废话不多说,是时候拉出来溜溜了:
// An highlighted block
package design.state.gys.state;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
CandyMachine cm=new CandyMachine(5);
cm.insertQuuarter();
cm.ejectQuarter();
cm.insertQuuarter();
cm.insertQuuarter();
cm.turnCrack();
cm.turnCrack();
}
}
看看结果吧:
// An highlighted block
投入硬币
正在退币
投入硬币
已经投入硬币,转动摇杆吧
转动摇杆,请稍后
掉落糖果
未投入硬币,无法摇动摇杆
一样实现了原来的功能。好了,圆满完成了公司的任务。