设计模式之状态模式

什么是状态模式

概念引入:状态模式是一种基于状态设计行为的模式。当我们需要设计这样一个系统:这个系统有许多状态,且对这个系统进行操作的有许多种方法,在系统的不同状态下,执行这些操作会导致不同的结果。这时就需要状态模式的设计理念来组织我们的代码了,以应对在多操作种类下的多状态之间的转化。
直接来分析一个例题,试着用状态模式的理念去实现。
如图
在这里插入图片描述
简单分析一下:这是一个与糖果贩卖机有关的题,糖果贩卖机有四个状态:售罄、有糖果但是没有投币、有糖果且投币了、售出糖果。对应的操作有投入25分钱,返回25分钱,转动曲柄,发放糖果这个几个操作。如果直接面向过程编程或许也可以解决这个问题,但是程序中会出现大量的if,else之类的语句,程序在后期也是完全不利于维护的。我们需要采用面向接口编程的设计思想去考虑这个问题。分析程序中变化的与不变的地方,四个状态与四个操作,在每个状态下我们都可以进行这四个操作,但是反馈不同,这里可以抽象为执行相同的方法,但是方法的具体执行内容不同,对应的状态转化不同。为了便于维护与扩展,我们把状态抽象出来作为接口,四种操作也就对应了四种抽象方法,子类继承后需要去具体实现。
总结一下,如何实现
1、写一个接口,包含四种操作(抽象方法)。
2、写四个状态的实现类,分别实现接口,重写方法,方法中包括状态的转化与具体的实现内容。
3、写一个糖果机器的类,在实例化它的时候也实例化四个状态对应的对象,也就说让它持有四个状态的引用,并为它们写get和set方法,把机器对象传入那些状态类,以便对状态进行操作。
流程的部分分析:程序可以设定初始状态,假定在没有25分钱的情况下,投入了25分钱,即机器对象调用了机器对象的投入25分钱的方法,在方法中实际上是当前state对象调用了自己的“投入25分钱”的方法,在这个方法中,令机器对象获取“有25分钱”这个状态的引用并用set方法设置当前状态为“有25分钱的状态”,系统同时输出相应的反馈。这是一个小步骤,但通过这个步骤也足以窥见整体的设计思路了。
这样设计的好处:以后如果要增加或者修改状态,只需要对这些被抽离出来的类单独进行调整就可以了,而不用修改客户代码,客户代码也仅仅持有状态的引用,而不知道具体的内容,这就实现了客户代码和具体行为的解耦。
和策略模式的区别:两者都把需要改变的行为抽象出来了,且都是动态改变。区别是状态模式对于状态之间的转化关系都是严密设计好的,类似于上述图示,过程都有严密的逻辑关系,而策略模式没有体现这个特点。

Java实现糖果售货机

一、状态接口

public interface State {
	public abstract void giveOutCandies();	
	public abstract void addMoney();	
	public abstract void giveBackMoney();	
	public abstract void turnHandle();		
}

1、糖果卖完的状态类

public class SoldOut implements State{
    private Machine machine;    
	public SoldOut(Machine machine) {
	      this.machine=machine;
	}			
	public void giveOutCandies() {
        System.out.println("没有糖果,不能分发");
	}
	public void addMoney() {
		 System.out.println("没有糖果,放入钱也没有用");		
	}	
	public void giveBackMoney() {
		System.out.println("没有糖果,取不出钱");		
	}	
	public void turnHandle() {
		System.out.println("没有糖果,转动手柄,没有现象");		
	}
}

** 2、机器没有得到钱的状态(还没有用户塞钱进去)**:

public class NoMoney implements State{
	private Machine machine;
	public NoMoney(Machine machine) {
		this.machine=machine;
	}	
	public void giveOutCandies() {
		System.out.println("当前没有糖果可以取出");		
	}	
	public void addMoney() {
	   System.out.println("加钱");
	   System.out.println("进入有钱的状态");
	   machine.setState(machine.getHaveMoney());
	}	
	public void giveBackMoney() {
		System.out.println("没有钱可以退");		
	}	
	public void turnHandle() {
		System.out.println("转动手柄,没有反应");		
	}
}

** 3、机器获得钱的状态(用户塞钱进去了)**:

public class HaveMoney implements State{
	private Machine machine;
	public HaveMoney(Machine machine) {
		this.machine=machine;
	}	
	public void giveOutCandies() {
		System.out.println("当前糖果还不能取出来");		
	}
	public void addMoney() {
		System.out.println("已经收到钱了,不需要再加钱");		
	}	
	public void giveBackMoney() {
		System.out.println("退钱成功");
		System.out.println("回到等待加钱的状态");
		machine.setState(machine.getNoMoney());
	}
	public void turnHandle() {
		System.out.println("转动手柄,请准备取糖果");
		machine.setState(machine.getSoldCandy());;
	}
}

** 4、机器准备出糖果的状态**:

public class SoldCandy implements State{
	private Machine machine;
	public SoldCandy(Machine machine) {
		this.machine=machine;
	}	
	public void giveOutCandies() {
		System.out.println("从机器获取糖果成功");
		machine.setCount(machine.getCount()-1);
		if(machine.getCount()==0){
			System.out.println("没糖果了");
		    machine.setState(machine.getSoldOut());
		}else{
			System.out.println("还有糖果继续卖");
			machine.setState(machine.getNoMoney());
		}
	}
	public void addMoney() {
		System.out.println("不能加钱,还有糖果没有拿出来呢");		
	}	
	public void giveBackMoney() {
		System.out.println("不能退钱,还有糖果没有拿出来呢");		
	}	
	public void turnHandle() {
		System.out.println("转动手柄无效,有糖果未取出");		
	}
}

** 二、卖糖果机器的类**:

public class Machine {
    //四个状态的引用
    private SoldCandy soldCandy;
    private SoldOut soldOut;
    private HaveMoney haveMoney;
    private NoMoney noMoney;
    private State state;//当前状态
    private int count;//糖果数
    /**
     * 构造方法
     * @param count
     */
	public Machine(int count) {
		this.count=count;
		soldCandy = new SoldCandy(this);
		soldOut=new SoldOut(this);
		haveMoney=new HaveMoney(this);
		noMoney=new NoMoney(this);
		state=noMoney;
	}
	/**
	 * 获取当前糖果数量
	 * @return
	 */
	public int getCount() {
		return this.count;
	}
	/**
	 * 设置糖果数
	 * @param count
	 */
	public void setCount(int count){
		this.count=count;
	}
	/**
	 * 出糖果
	 */
	public void giveOutCandies(){
		state.giveOutCandies();
	}
	/**
	 * 放入钱
	 */
	public void addMoney(){
		state.addMoney();
	}
	/**
	 * 退出钱
	 */
	public void giveBackMoney(){
		state.giveBackMoney();
	}
	/**
	 * 转动手柄
	 */
	public void turnHandle(){
		state.turnHandle();
	}	
	public SoldCandy getSoldCandy() {
		return soldCandy;
	}
	public SoldOut getSoldOut() {
		return soldOut;
	}
	public HaveMoney getHaveMoney() {
		return haveMoney;
	}
	public NoMoney getNoMoney() {
		return noMoney;
	}
	/**
	 * 设置状态
	 * @param state
	 */
    public void setState(State state){
    	this.state=state;
    }	
}

** 三、测试类**:

public class Test {	
	public static void main(String[] args){
		Machine mc=new Machine(5);		
		mc.addMoney();
		mc.turnHandle();
		mc.giveOutCandies();		
		System.out.println("+++++++++++++++++++++++");		
		mc.addMoney();
		mc.giveBackMoney();
		mc.addMoney();
		mc.turnHandle();
		mc.giveOutCandies();		
		System.out.println("+++++++++++++++++++++++");		
		mc.addMoney();
		mc.turnHandle();
		mc.giveOutCandies();
		mc.addMoney();
		mc.turnHandle();
		mc.giveOutCandies();
		mc.addMoney();
		mc.turnHandle();
		mc.giveOutCandies();
		mc.addMoney();
		mc.turnHandle();
		mc.giveOutCandies();			
	}	
}

** 四、运行结果**:
在这里插入图片描述
简单分析一下测试的过程:先塞钱给机器,然后转动手柄,再取糖果;然后测试了退钱的操作;最后一口气把糖果取完,测试当糖果没有后的状态输出。结果和设计的以及预想的一致,实现了通过机器的状态转化功能。
小结:面对有多个状态的系统,同时也有多种操作,就可以用状态模式来设计这个系统,这可以充分考虑到每一个变化的状态,也能为后期的状态修改创造条件,同时客户代码仅仅持有状态的引用,而不关心其具体内容,这就实现了具体状态和状态调用的解耦。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值