设计模式-状态模式

模式介绍

如果我们在编写代码的时候,遇到大量的条件判断的时候,可能会采用策略模式来优化结构,因为这时涉及到策略的选择,但有时候仔细查看下,就会发现,这些所谓的策略其实是对象的不同状态,更加明显的是,对象的某种状态也成为判断的条件

实例

一个类对外提供了多个行为,同时该类对象有多种状态,不同状态下对外的行为的表现不同,比如无人自动咖啡售卖机开发一个控制程序。

用户可以再咖啡机上进行支付、退款、购买、取咖啡操作

不同状态下,这四种操作将有不同的表现。比如在没有支付的状态下,用户在咖啡机上点退款、购买、取咖啡,和在已支付的状态下做着三个操作时不一样的。
在这里插入图片描述
面对这样的需求,你可能会写出这样的代码:

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

	}
}

总结

  • 要使用状态模式,我们必须明确两个东西:状态和每个状态下执行的动作
  • 在状态模式中,因为所有的状态都要执行相应的动作,所以我们可以考虑将状态抽象出来
  • 状态的抽象一般有两种形式:接口和抽象类。如果所有的状态都有共同的数据域,可以使用抽象类,但如果只是单纯的执行动作,就可以使用接口
  • 状态模式的好处就是将我们从这个复杂的嵌套条件中脱离出来,但状态模式的坏处也是非常明显:需要管理一系列的状态类
  • 策略模式侧重的是一个行为的多个算法实现,可互换算法;命令模式侧重的是为多个行为提供灵活的执行方式;状态模式,应用于状态机的情况
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值