设计模式学习笔记之状态模式

Posted birdlove1987

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式学习笔记之状态模式相关的知识,希望对你有一定的参考价值。

什么是状态模式呢?

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。。。是不是听起来显示在内部进行零件调换的感觉,其实是有点类似这种想法的,只不过调换的零件就是封装好的状态。

让我们来举个例子




在我还上学的时候,寝室楼下有一台这样的自动贩售机,专门卖饮料。每天晚上寝室关门之后口渴了,在这里面买点饮料喝喝还是很方便的。

下面用程序来模拟一下这个售货机:


可乐售货机类:


/**
 * 
 * 可乐自动贩售机类
 * @author birdlove1987
 *
 */
public class VendingMachine 

	
	//售空
	final static int SoldOutState = 0;
	
	//在售
	final static int OnReadyState = 1;
	
	//有币
	final static int HasCoin = 2;
	
	//出货
	final static int SoldState = 3;

	//售货机状态
	private int state = SoldOutState;
	
	//机内可乐数量
	private int count = 0;

	//构造函数,初始化自动贩售机
	public VendingMachine(int count) 
	
		this.count = count;
		if (count > 0) 
			state = OnReadyState;
		
	

	//向贩售机投币函数
	public void insertCoin()
	
		switch (state)
		
			case SoldOutState:
				System.out.println("请不要投币了,售货机里已经没有可乐了!");
				break;
			case OnReadyState:
				state = HasCoin;
				System.out.println("投币成功,请按出货按钮!");
				break;
			case HasCoin:
				System.out.println("售货机里以及有硬币了,请勿重复投币!");
				break;
			case SoldState:
				System.out.println("正在出货请勿投币!");
				break;
		
	

	//贩售机退币函数
	public void returnCoin() 
	
		switch (state)
		
			case SoldOutState:
				System.out.println("您还没有投币!");
				break;
			case OnReadyState:
				System.out.println("您还没有投币!");
				break;
			case HasCoin:
				System.out.println("请在退币口收好您的硬币");
				state = OnReadyState;
				break;
			case SoldState:
				System.out.println("可乐已售出,不能退币");
				break;
		
	

	//按出可乐按钮函数
	public void pressButton() 
	
		switch (state) 
		
			case SoldOutState:
				System.out.println("对不起,可乐已售空!");
				break;
			case OnReadyState:
				System.out.println("请您先投币!");
				break;
			case HasCoin:
				System.out.println("请稍等,出可乐中!");
				state = SoldState;
				appearCola();
				break;
			case SoldState:
				System.out.println("可乐已出,如想再次购买请再次投币!");
			break;
		
	

	//售货机出可乐函数
	private void appearCola() 
	
		count = count - 1;
		System.out.println("出货口,滚出了一瓶可乐!");
		if (count > 0)
		
			state = OnReadyState;
		 
		else
		
			System.out.println("对不起,可乐已经售空了,请勿在投币!");
			state = SoldOutState;
		
	

	//打印目前售货机的状态
	public void printState() 
	
		switch (state) 
		
			case SoldOutState:
				System.out.println("=========售空=========");
				break;
			case OnReadyState:
				System.out.println("=========售卖中=========");
				break;
			case HasCoin:
				System.out.println("=========已投币=========");
				break;
			case SoldState:
				System.out.println("=========出货中=========");
				break;
		
	


写个测试类来测试一下

测试类


/**
 * 测试类
 * @author birdlove1987
 *
 */
public class MainTest 

	public static void main(String[] args) 
	
		//创建售货机实例,并且只放入一瓶可乐
		VendingMachine mVendingMachine=new VendingMachine(1);
		
		
		//打印售货机状态
		mVendingMachine.printState();
		
		//投币
		mVendingMachine.insertCoin();
		
		//打印售货机状态
		mVendingMachine.printState();
		
		//按出货按钮
		mVendingMachine.pressButton();
		
		
		//打印售货机状态
		mVendingMachine.printState();
		
		//投币
		mVendingMachine.insertCoin();
		
		//打印售货机状态
		mVendingMachine.printState();
		
		//按出货按钮
		mVendingMachine.pressButton();
		
		//打印售货机状态
		mVendingMachine.printState();
	



嗯!模拟成功了!好像感觉还不错呢!不过买了一段时间,你可能发现,如果不搞一些促销活动,更本就搞不过那些有促销的商家!




所以自动售货机也要搞一个“再来一瓶”的活动啊!

但是!!!如果现在直接在自动售货机的类上去直接修改,就违背了软件设计里的“开-闭原则”了,破坏了我们已经闭合的类。所以现在看来,这种设计并不好。。

下面就轮到状态设计模式登场啦,我们从新构建类,这次以状态为类,来构建。

首先定义一下状态接口


/***
 * 状态接口
 * @author birdlove1987
 *
 */
public interface State 

	
	//投币函数
	public void insertCoin();
	
	//退币函数
	public void returnCoin();
	
	//按出可乐按钮函数
	public void pressButton();
	
	//出可乐函数
	public void appearCola();
	
	//打印状态函数
	public void printState();
	


再来定义状态类


/***
 * 在售状态类
 * @author birdlove1987
 *
 */
public class OnReadyState implements State 

	
	//贩售机引用
	private VendingMachine mVendingMachine;
	
	//构造函数初始化
	public OnReadyState(VendingMachine mVendingMachine)
	
		this.mVendingMachine=mVendingMachine;
	

	
	@Override
	public void insertCoin() 
	
		// TODO Auto-generated method stub
		System.out.println("投币成功,请按出货按钮!");
		mVendingMachine.setState(mVendingMachine.mHasCoin);
	

	@Override
	public void returnCoin() 
	
		// TODO Auto-generated method stub
		System.out.println("您还没有投币!");
		
	

	@Override
	public void pressButton() 
	
		// TODO Auto-generated method stub
		System.out.println("请您先投币!");
		
	

	@Override
	public void appearCola() 
	
		// TODO Auto-generated method stub
	

	@Override
	public void printState() 
	
		// TODO Auto-generated method stub
		System.out.println("=========售卖中=========");
	



/***
 * 售空状态类
 * @author birdlove1987
 *
 */
public class SoldOutState implements State 


	private VendingMachine mVendingMachine;
	public SoldOutState(VendingMachine mCandyMachine)
	
		this.mVendingMachine=mVendingMachine;
	

	@Override
	public void insertCoin() 
	
		// TODO Auto-generated method stub
		System.out.println("请不要投币了,售货机里已经没有可乐了!");
		
	

	@Override
	public void returnCoin() 
	
		// TODO Auto-generated method stub
		System.out
		.println("您还没有投币!");

	

	@Override
	public void pressButton() 
	
		// TODO Auto-generated method stub
		System.out.println("对不起,可乐已售空!");
		
	

	@Override
	public void appearCola() 
	
		// TODO Auto-generated method stub

	

	@Override
	public void printState() 
		// TODO Auto-generated method stub
		System.out.println("=========售空=========");
	
	




/***
 * 已投币状态类
 * @author birdlove1987
 *
 */
public class HasCoin implements State 
	
	private VendingMachine mVendingMachine;
	public HasCoin(VendingMachine mVendingMachine) 
	
		this.mVendingMachine = mVendingMachine;
	

	@Override
	public void insertCoin() 
	
		// TODO Auto-generated method stub
		System.out.println("售货机里以及有硬币了,请勿重复投币!");

	

	@Override
	public void returnCoin()
	
		// TODO Auto-generated method stub
		System.out.println("请在退币口收好您的硬币");
		mVendingMachine.setState(mVendingMachine.mOnReadyState);
	

	@Override
	public void pressButton()
	
		// TODO Auto-generated method stub
		System.out.println("请稍等,出可乐中!");
		
		//创建随机中奖概率
		Random anotherOne = new Random();
		
		//20%的机会再来一瓶
		int luck = anotherOne.nextInt(5);
		if(luck==0)
		
			mVendingMachine.setState(mVendingMachine.mOneMoreCola);
		else
		
			mVendingMachine.setState(mVendingMachine.mSoldState);
		
	

	@Override
	public void appearCola()
	
	

	@Override
	public void printState() 
	
		// TODO Auto-generated method stub
		System.out.println("=========已投币=========");

	



/**
 * 出可乐状态类
 * @author birdlove1987
 *
 */
public class SoldState implements State 

	private VendingMachine mVendingMachine;
	public SoldState(VendingMachine mVendingMachine)
	
		this.mVendingMachine=mVendingMachine;
	

	@Override
	public void insertCoin() 
	
		// TODO Auto-generated method stub
		System.out.println("正在出货请勿投币!");
	

	@Override
	public void returnCoin() 
	
		// TODO Auto-generated method stub
		System.out.println("可乐已售出,不能退币");
		
	

	@Override
	public void pressButton()
	
		// TODO Auto-generated method stub
		System.out
		.println("可乐已出,如想再次购买请再次投币!");

	

	@Override
	public void appearCola() 
	
		// TODO Auto-generated method stub
		
		mVendingMachine.appearCola();
		if (mVendingMachine.getCount() > 0) 
		
			mVendingMachine.setState(mVendingMachine.mOnReadyState);
		
		else 
		
			System.out.println("对不起,可乐已经售空了,请勿在投币!");
			mVendingMachine.setState(mVendingMachine.mSoldOutState);
		
	
	
	@Override
	public void printState()
	
		// TODO Auto-generated method stub
		System.out.println("=========出货中=========");	
	




/***
 * 再来一瓶类
 * @author birdlove1987
 *
 */
public class OneMoreCola implements State 


	private VendingMachine mVendingMachine;

	public OneMoreCola(VendingMachine mVendingMachine) 
	
		this.mVendingMachine = mVendingMachine;
	

	@Override
	public void insertCoin() 
	
		// TODO Auto-generated method stub
		System.out.println("正在出货请勿投币!");
	

	@Override
	public void returnCoin() 
	
		// TODO Auto-generated method stub
		System.out.println("可乐已售出,不能退币");

	

	@Override
	public void pressButton() 
	
		// TODO Auto-generated method stub
		System.out.println("请稍等,出可乐中!");

	

	@Override
	public void appearCola() 
	
		// TODO Auto-generated method stub

		
		mVendingMachine.appearCola();
		if (mVendingMachine.getCount() == 0) 
		
			mVendingMachine.setState(mVendingMachine.mSoldOutState);
		 
		else 
		
			System.out.println("恭喜你获得了再来一瓶,马上为您再出一瓶可乐");
			mVendingMachine.appearCola();
			if (mVendingMachine.getCount() > 0) 
			
				mVendingMachine.setState(mVendingMachine.mOnReadyState);
			
			else 
			
				System.out.println("对不起,可乐已经售空了,请勿在投币!");
				mVendingMachine.setState(mVendingMachine.mSoldOutState);
			
		

	

	@Override
	public void printState() 
	
		// TODO Auto-generated method stub
		System.out.println("=========再来一瓶=========");
	







构建自动贩售机类


/**
 * 自动售货机类
 * @author birdlove1987
 *
 */
public class VendingMachine 

	//状态类引用
	State mSoldOutState;
	State mOnReadyState;
	State mHasCoin;
	State mSoldState;
	State mOneMoreCola;
	
	//目前状态
	private State state;
	
	//可乐计数器
	private int count = 0;

	//构造函数
	public VendingMachine(int count) 
	
		this.count = count;
		mSoldOutState = new SoldOutState(this);
		mOnReadyState = new OnReadyState(this);
		mHasCoin = new HasCoin(this);
		mSoldState = new SoldState(this);
		mOneMoreCola = new OneMoreCola(this);
		if (count > 0) 
		
			state = mOnReadyState;
		
		else 
		
			state = mSoldOutState;
		
	

	//设置状态函数
	public void setState(State state) 
	
		this.state = state;
	

	//投币函数
	public void insertCoin() 
	
		state.insertCoin();
	
	
	//退币函数
	public void returnCoin() 
	
		state.returnCoin();
	
	
	//按出可乐按钮函数
	public void pressButton() 
	
		state.pressButton();
		state.appearCola();
	

	//出可乐函数
	void appearCola() 
	
		// TODO Auto-generated method stub
		if (count > 0)
		
			count = count - 1;
			System.out.println("出货口,滚出了一瓶可乐!");
		

	

	//可乐计数函数
	public int getCount() 
	
		return count;
	
	
	//打印状态函数
	public void printState() 
	
		state.printState();
	


最后写一个测试类测试一下


/**
 * 测试类
 * @author birdlove1987
 *
 */
public class MainTest 

	public static void main(String[] args) 
	
		
		//实例化自动贩售机对象
		VendingMachine mVendingMachine = new VendingMachine(10);
		
		//打印状态
		mVendingMachine.printState();

		//投币
		mVendingMachine.insertCoin();
		
		//打印状态
		mVendingMachine.printState();

		//按出可乐按钮
		mVendingMachine.pressButton();

		//打印状态
		mVendingMachine.printState();

		//投币
		mVendingMachine.insertCoin();
		
		//打印状态
		mVendingMachine.printState();

		//按出可乐按钮
		mVendingMachine.pressButton();

		//打印状态
		mVendingMachine.printState();
	




卧槽!一次都没中奖,什么鬼!!!不行,买买买!!!




中了一次。。。好吧,我来作弊一下。。调到100%




哈哈哈!


状态模式的优点
    1.状态模式将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
    2.将与状态有关的行为封装到一个类中,方便地增加新的状态,只需改变对象状态即可改变对象的行为。 
    3.提供代码复用性,降低了程序的某些耦合性。   
     
状态模式的缺点
    1.有时候状态类会很多,而且逻辑复杂。

状态模式适用场景
    1、对象的行为依赖于它的状态,并且其行为依据它的状态改变而改变。 
    2、代码中包含大量与对象状态有关的条件语句







以上是关于设计模式学习笔记之状态模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式学习笔记 之 状态模式

Java学习笔记——设计模式之十.观察者模式

设计模式之观察者模式学习笔记

设计模式之观察者模式学习笔记

设计模式之观察者模式学习笔记

SpringCloud之学习笔记(Feign+consul)