模式介绍
如果我们在编写代码的时候,遇到大量的条件判断的时候,可能会采用策略模式来优化结构,因为这时涉及到策略的选择,但有时候仔细查看下,就会发现,这些所谓的策略其实是对象的不同状态,更加明显的是,对象的某种状态也成为判断的条件
实例
一个类对外提供了多个行为,同时该类对象有多种状态,不同状态下对外的行为的表现不同,比如无人自动咖啡售卖机开发一个控制程序。
用户可以再咖啡机上进行支付、退款、购买、取咖啡操作
不同状态下,这四种操作将有不同的表现。比如在没有支付的状态下,用户在咖啡机上点退款、购买、取咖啡,和在已支付的状态下做着三个操作时不一样的。
面对这样的需求,你可能会写出这样的代码:
public class CoffeeMachine {
final static int NO_PAY = 0;
final static int PAY = 1;
final static int SOLD = 2;
final static int SOLD_OUT = 4;
private int state = SOLD_OUT;
private int store;
public CoffeeMachine(int store) {
this.store = store;
if (this.store > 0) {
this.state = NO_PAY;
}
}
public void pay() {
switch (this.state) {
case NO_PAY:
System.out.println("支付成功,请确定购买咖啡。");
this.state = PAY;
break;
case PAY:
System.out.println("已支付成功,请确定购买咖啡。");
break;
case SOLD:
System.out.println("待取咖啡中,请稍后购买!");
break;
case SOLD_OUT:
System.out.println("咖啡已售罄,不可购买!");
}
}
public void refund() {
switch (this.state) {
case NO_PAY:
System.out.println("你尚未支付,请不要乱按!");
break;
case PAY:
System.out.println("退款成功!");
this.state = NO_PAY;
break;
case SOLD:
System.out.println("已购买,请取用!");
break;
case SOLD_OUT:
System.out.println("咖啡已售罄,不可购买!");
}
}
// 购买
public void buy() {
switch (this.state) {
case NO_PAY:
System.out.println("你尚未支付,请不要乱按!");
break;
case PAY:
System.out.println("购买成功,请取用!");
this.state = SOLD;
break;
case SOLD:
System.out.println("已购买,请取用!");
break;
case SOLD_OUT:
System.out.println("咖啡已售罄,不可购买!");
}
}
// 取coffee
public void getCoffee() {
switch (this.state) {
case NO_PAY:
System.out.println("你尚未支付,请不要乱按!");
break;
case PAY:
System.out.println("已购买,请取用!");
break;
case SOLD:
System.out.println("请放好杯子,3秒后将出咖啡!");
this.store--;
if (this.store == 0) {
this.state = SOLD_OUT;
} else {
this.state = NO_PAY;
}
break;
case SOLD_OUT:
System.out.println("咖啡已售罄,不可购买!");
}
}
}
这种写法,如果新增一种状态或者改变状态的行为,那么改动特别大,极其难以维护,因此我们接下来使用状态模式来解决这个问题
模式类图
代码实例
改进上面的例子,使用状态模式
咖啡机代码:
public class NewCoffeeMachine {
final State NO_PAY, PAY, SOLD, SOLD_OUT;
State state;
int store;
public NewCoffeeMachine(int store) {
NO_PAY = new NoPayState(this);
PAY = new PayState(this);
SOLD = new SoldState(this);
SOLD_OUT = new SoldOutState(this);
this.store = store;
if (this.store > 0) {
this.state = NO_PAY;
}
}
public void pay() {
this.state.pay();
}
public void refund() {
this.state.refund();
}
public void buy() {
this.state.buy();
}
public void getCoffee() {
this.state.getCoffee();
}
}
状态接口类:
public interface State {
void pay();
void refund();
void buy();
void getCoffee();
}
未支付状态实现类:
public class NoPayState implements State {
private NewCoffeeMachine machine;
public NoPayState(NewCoffeeMachine machine) {
this.machine = machine;
}
@Override
public void pay() {
System.out.println("支付成功,请去确定购买咖啡。");
this.machine.state = this.machine.PAY;
}
@Override
public void refund() {
System.out.println("你尚未支付,请不要乱按!");
}
@Override
public void buy() {
System.out.println("你尚未支付,请不要乱按!");
}
@Override
public void getCoffee() {
System.out.println("你尚未支付,请不要乱按!");
}
}
支付状态实现类:
public class PayState implements State {
private NewCoffeeMachine machine;
public PayState(NewCoffeeMachine machine) {
this.machine = machine;
}
@Override
public void pay() {
System.out.println("您已支付,请去确定购买!");
}
@Override
public void refund() {
System.out.println("退款成功,请收好!");
this.machine.state = this.machine.NO_PAY;
}
@Override
public void buy() {
System.out.println("购买成功,请取用");
this.machine.state = this.machine.SOLD;
}
@Override
public void getCoffee() {
System.out.println("请先确定购买!");
}
}
售出状态实现类:
public class SoldState implements State {
private NewCoffeeMachine machine;
public SoldState(NewCoffeeMachine machine) {
this.machine = machine;
}
@Override
public void pay() {
}
@Override
public void refund() {
// TODO Auto-generated method stub
}
@Override
public void buy() {
// TODO Auto-generated method stub
}
@Override
public void getCoffee() {
// TODO Auto-generated method stub
}
}
售罄状态实现类:
public class SoldOutState implements State {
private NewCoffeeMachine machine;
public SoldOutState(NewCoffeeMachine machine) {
this.machine = machine;
}
@Override
public void pay() {
}
@Override
public void refund() {
// TODO Auto-generated method stub
}
@Override
public void buy() {
// TODO Auto-generated method stub
}
@Override
public void getCoffee() {
// TODO Auto-generated method stub
}
}
总结
- 要使用状态模式,我们必须明确两个东西:状态和每个状态下执行的动作
- 在状态模式中,因为所有的状态都要执行相应的动作,所以我们可以考虑将状态抽象出来
- 状态的抽象一般有两种形式:接口和抽象类。如果所有的状态都有共同的数据域,可以使用抽象类,但如果只是单纯的执行动作,就可以使用接口
- 状态模式的好处就是将我们从这个复杂的嵌套条件中脱离出来,但状态模式的坏处也是非常明显:需要管理一系列的状态类
- 策略模式侧重的是一个行为的多个算法实现,可互换算法;命令模式侧重的是为多个行为提供灵活的执行方式;状态模式,应用于状态机的情况