• 设计模式 State模式 机器的情况下用自己的主动性


    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/26350617

    状态模型给我眼前一亮的感觉啊,值得学习~

    看看定义:改变一个对象的内部状态的改变行为认同,对象出现改变它的类。糊了,理一下。当对象的内部状态改变时,它的行为尾随状态的改变而改变了。看起来好像又一次初始化了一个相似的。

    以下使用个样例来说明状态模式的使用方法,如今有个自己主动售货机的代码须要我们来写,状态图例如以下:


    分析一个这个状态图:

    a、包括4个状态(我们使用4个int型常量来表示)

    b、包括3个暴露在外的方法(投币、退币、转动手柄)

    c、我们须要处理每一个状态下,用户都能够触发这三个动作。

    以下我们依据分析的结果。写出代码:

    package com.zhy.pattern.status;
    
    /**
     * 自己主动售货机
     * 
     * @author zhy
     * 
     */
    public class VendingMachine
    {
    
    	/**
    	 * 已投币
    	 */
    	private final static int HAS_MONEY = 0;
    	/**
    	 * 未投币
    	 */
    	private final static int NO_MONEY = 1;
    	/**
    	 * 售出商品
    	 */
    	private final static int SOLD = 2;
    	/**
    	 * 商品售罄
    	 */
    	private final static int SOLD_OUT = 3;
    
    	private int currentStatus = NO_MONEY;
    	/**
    	 * 商品数量
    	 */
    	private int count = 0;
    
    	public VendingMachine(int count)
    	{
    		this.count = count;
    		if (count > 0)
    		{
    			currentStatus = NO_MONEY;
    		}
    	}
    
    	/**
    	 * 投入硬币,不论什么状态用户都可能投币
    	 */
    	public void insertMoney()
    	{
    		switch (currentStatus)
    		{
    		case NO_MONEY:
    			currentStatus = HAS_MONEY;
    			System.out.println("成功投入硬币");
    			break;
    		case HAS_MONEY:
    			System.out.println("已经有硬币,无需投币");
    			break;
    		case SOLD:
    			System.out.println("请稍等...");
    			break;
    		case SOLD_OUT:
    			System.out.println("商品已经售罄,请勿投币");
    			break;
    
    		}
    	}
    
    	/**
    	 * 退币,不论什么状态用户都可能退币
    	 */
    	public void backMoney()
    	{
    		switch (currentStatus)
    		{
    		case NO_MONEY:
    			System.out.println("您未投入硬币");
    			break;
    		case HAS_MONEY:
    			currentStatus = NO_MONEY;
    			System.out.println("退币成功");
    			break;
    		case SOLD:
    			System.out.println("您已经买了糖果...");
    			break;
    		case SOLD_OUT:
    			System.out.println("您未投币...");
    			break;
    		}
    	}
    
    	/**
    	 * 转动手柄购买,不论什么状态用户都可能转动手柄
    	 */
    	public void turnCrank()
    	{
    		switch (currentStatus)
    		{
    		case NO_MONEY:
    			System.out.println("请先投入硬币");
    			break;
    		case HAS_MONEY:
    			System.out.println("正在出商品....");
    			currentStatus = SOLD;
    			dispense();
    			break;
    		case SOLD:
    			System.out.println("连续转动也没用...");
    			break;
    		case SOLD_OUT:
    			System.out.println("商品已经售罄");
    			break;
    
    		}
    	}
    
    	/**
    	 * 发放商品
    	 */
    	private void dispense()
    	{
    
    		switch (currentStatus)
    		{
    		case NO_MONEY:
    		case HAS_MONEY:
    		case SOLD_OUT:
    			throw new IllegalStateException("非法的状态...");
    		case SOLD:
    			count--;
    			System.out.println("发出商品...");
    			if (count == 0)
    			{
    				System.out.println("商品售罄");
    				currentStatus = SOLD_OUT;
    			} else
    			{
    				currentStatus = NO_MONEY;
    			}
    			break;
    
    		}
    
    	}
    }
    

    针对用户的每一个动作,我们考虑了在不论什么状态下发生,并做了一定处理。以下进行一些測试:

    package com.zhy.pattern.status;
    
    public class TestTra
    {
    	public static void main(String[] args)
    	{
    		VendingMachine machine = new VendingMachine(10);
    		machine.insertMoney();
    		machine.backMoney();
    
    		System.out.println("-----------");
    
    		machine.insertMoney();
    		machine.turnCrank();
    		
    		System.out.println("----------压力測试-----");
    		machine.insertMoney();
    		machine.insertMoney();
    		machine.turnCrank();
    		machine.turnCrank();
    		machine.backMoney();
    		machine.turnCrank();
    
    	}
    }
    
    输出结果:
    成功投入硬币
    退币成功
    -----------
    成功投入硬币
    正在出商品....
    发出商品...
    ----------压力測试-----
    成功投入硬币
    已经有硬币。无需投币
    正在出商品....
    发出商品...
    请先投入硬币
    您未投入硬币
    请先投入硬币
    
    感觉还是不错的,基本实现了功能,可是有些事情是不可避免的,那就是需求的变化,如今为了提升销量,当用户每次转动手柄买商品的时候,有10%的几率赠送一瓶。

    如今的状态图发生了变化,当用户转动手柄时,可能会达到一个中奖的状态:图例如以下:

    假设在我们刚写的代码上直接加入。则须要在每一个动作的switch中加入推断条件,且很easy出错。所以如今我们要考虑又一次设计我们的代码,我们考虑把每一个状态写状态类。负责实如今相应动作下的行为,然后自己主动售货机在不能的状态间切换:

    以下開始重构,我们如今有5种状态。相应4个动作(投币、退币、转动手柄、发出商品),以下首先定义一个状态的超类型:

    package com.zhy.pattern.status.b;
    
    /**
     * 状态的接口
     * @author zhy
     *
     */
    public interface State
    {
    	/**
    	 * 放钱
    	 */
    	public void insertMoney();
    	/**
    	 * 退钱
    	 */
    	public void backMoney();
    	/**
    	 * 转动曲柄
    	 */
    	public void turnCrank();
    	/**
    	 * 出商品
    	 */
    	public void dispense();
    }
    

    然后各自是每一个状态的实现:

    package com.zhy.pattern.status.b;
    
    /**
     * 没钱的状态
     * @author zhy
     *
     */
    public class NoMoneyState implements State
    {
    
    	private VendingMachine machine;
    
    	public NoMoneyState(VendingMachine machine)
    	{
    		this.machine = machine;
    		
    	}
    	
    	@Override
    	public void insertMoney()
    	{
    		System.out.println("投币成功");
    		machine.setState(machine.getHasMoneyState());
    	}
    
    	@Override
    	public void backMoney()
    	{
    		System.out.println("您未投币,想退钱?...");
    	}
    
    	@Override
    	public void turnCrank()
    	{
    		System.out.println("您未投币,想拿东西么?...");
    	}
    
    	@Override
    	public void dispense()
    	{
    		throw new IllegalStateException("非法状态。");
    	}
    
    }
    

    package com.zhy.pattern.status.b;
    
    import java.util.Random;
    
    /**
     * 已投入钱的状态
     * 
     * @author zhy
     * 
     */
    public class HasMoneyState implements State
    {
    
    	private VendingMachine machine;
    	private Random random = new Random();
    
    	public HasMoneyState(VendingMachine machine)
    	{
    		this.machine = machine;
    	}
    
    	@Override
    	public void insertMoney()
    	{
    		System.out.println("您已经投过币了,无需再投....");
    	}
    
    	@Override
    	public void backMoney()
    	{
    		System.out.println("退币成功");
    
    		machine.setState(machine.getNoMoneyState());
    	}
    
    	@Override
    	public void turnCrank()
    	{
    		System.out.println("你转动了手柄");
    		int winner = random.nextInt(10);
    		if (winner == 0 && machine.getCount() > 1)
    		{
    			machine.setState(machine.getWinnerState());
    		} else
    		{
    			machine.setState(machine.getSoldState());
    		}
    	}
    
    	@Override
    	public void dispense()
    	{
    		throw new IllegalStateException("非法状态!

    "); } }


    package com.zhy.pattern.status.b;
    
    /**
     * 售罄的状态
     * 
     * @author zhy
     * 
     */
    public class SoldOutState implements State
    {
    
    	private VendingMachine machine;
    
    	public SoldOutState(VendingMachine machine)
    	{
    		this.machine = machine;
    	}
    
    	@Override
    	public void insertMoney()
    	{
    		System.out.println("投币失败。商品已售罄");
    	}
    
    	@Override
    	public void backMoney()
    	{
    		System.out.println("您未投币,想退钱么?...");
    	}
    
    	@Override
    	public void turnCrank()
    	{
    		System.out.println("商品售罄,转动手柄也木实用");
    	}
    
    	@Override
    	public void dispense()
    	{
    		throw new IllegalStateException("非法状态!");
    	}
    
    }
    

    package com.zhy.pattern.status.b;
    
    /**
     * 准备出商品的状态,该状态下,不会有不论什么用户的操作
     * 
     * @author zhy
     * 
     */
    public class SoldState implements State
    {
    
    	private VendingMachine machine;
    
    	public SoldState(VendingMachine machine)
    	{
    		this.machine = machine;
    	}
    
    	@Override
    	public void insertMoney()
    	{
    		System.out.println("正在出货,请勿投币");
    	}
    
    	@Override
    	public void backMoney()
    	{
    		System.out.println("正在出货,没有可退的钱");
    	}
    
    	@Override
    	public void turnCrank()
    	{
    		System.out.println("正在出货,请勿反复转动手柄");
    	}
    
    	@Override
    	public void dispense()
    	{
    		machine.dispense();
    		if (machine.getCount() > 0)
    		{
    			machine.setState(machine.getNoMoneyState());
    		} else
    		{
    			System.out.println("商品已经售罄");
    			machine.setState(machine.getSoldOutState());
    		}
    	}
    }
    

    package com.zhy.pattern.status.b;
    
    /**
     * 中奖的状态,该状态下不会有不论什么用户的操作
     * 
     * @author zhy
     * 
     */
    public class WinnerState implements State
    {
    
    	private VendingMachine machine;
    
    	public WinnerState(VendingMachine machine)
    	{
    		this.machine = machine;
    	}
    
    	@Override
    	public void insertMoney()
    	{
    		throw new IllegalStateException("非法状态");
    	}
    
    	@Override
    	public void backMoney()
    	{
    		throw new IllegalStateException("非法状态");
    	}
    
    	@Override
    	public void turnCrank()
    	{
    		throw new IllegalStateException("非法状态");
    	}
    
    	@Override
    	public void dispense()
    	{
    		System.out.println("你中奖了。恭喜你。将得到2件商品");
    		machine.dispense();
    
    		if (machine.getCount() == 0)
    		{
    			System.out.println("商品已经售罄");
    			machine.setState(machine.getSoldOutState());
    		} else
    		{
    			machine.dispense();
    			if (machine.getCount() > 0)
    			{
    				machine.setState(machine.getNoMoneyState());
    			} else
    			{
    				System.out.println("商品已经售罄");
    				machine.setState(machine.getSoldOutState());
    			}
    			
    		}
    
    	}
    
    }
    


    最后是自己主动售货机的代码:

    package com.zhy.pattern.status.b;
    
    /**
     * 自己主动售货机
     * 
     * @author zhy
     * 
     */
    public class VendingMachine
    {
    	private State noMoneyState;
    	private State hasMoneyState;
    	private State soldState;
    	private State soldOutState;
    	private State winnerState ; 
    
    	private int count = 0;
    	private State currentState = noMoneyState;
    
    	public VendingMachine(int count)
    	{
    		noMoneyState = new NoMoneyState(this);
    		hasMoneyState = new HasMoneyState(this);
    		soldState = new SoldState(this);
    		soldOutState = new SoldOutState(this);
    		winnerState = new WinnerState(this);
    
    		if (count > 0)
    		{
    			this.count = count;
    			currentState = noMoneyState;
    		}
    	}
    
    	public void insertMoney()
    	{
    		currentState.insertMoney();
    	}
    
    	public void backMoney()
    	{
    		currentState.backMoney();
    	}
    
    	public void turnCrank()
    	{
    		currentState.turnCrank();
    		if (currentState == soldState || currentState == winnerState)
    			currentState.dispense();
    	}
    
    	public void dispense()
    	{
    		System.out.println("发出一件商品...");
    		if (count != 0)
    		{
    			count -= 1;
    		}
    	}
    
    	public void setState(State state)
    	{
    		this.currentState = state;
    	}
    
    	//getter setter omitted ...
    
    }
    

    能够看到,我们如今把每一个状态相应于动作的行为局部化到了状态自己的类中实现,不仅添加了扩展性并且使代码的阅读性大幅度的提高。以后再加入状态,仅仅须要针对新加入的状态的实现类,并在自己主动售货机中加入此状态就可以。

    以下进行一些測试:

    package com.zhy.pattern.status.b;
    
    public class Test
    {
    	public static void main(String[] args)
    	{
    		VendingMachine machine = new VendingMachine(10);
    		machine.insertMoney();
    		machine.backMoney();
    
    		System.out.println("----我要中奖----");
    
    		machine.insertMoney();
    		machine.turnCrank();
    		machine.insertMoney();
    		machine.turnCrank();
    		machine.insertMoney();
    		machine.turnCrank();
    		machine.insertMoney();
    		machine.turnCrank();
    		machine.insertMoney();
    		machine.turnCrank();
    		machine.insertMoney();
    		machine.turnCrank();
    		machine.insertMoney();
    		machine.turnCrank();
    
    		System.out.println("-------压力測试------");
    
    		machine.insertMoney();
    		machine.backMoney();
    		machine.backMoney();
    		machine.turnCrank();// 无效操作
    		machine.turnCrank();// 无效操作
    		machine.backMoney();
    
    	}
    }
    

    输出结果:

    投币成功
    退币成功
    ----我要中奖----
    投币成功
    你转动了手柄
    发出一件商品...
    投币成功
    你转动了手柄
    发出一件商品...
    投币成功
    你转动了手柄
    发出一件商品...
    投币成功
    你转动了手柄
    发出一件商品...
    投币成功
    你转动了手柄
    发出一件商品...
    投币成功
    你转动了手柄
    发出一件商品...
    投币成功
    你转动了手柄
    你中奖了,恭喜你。将得到2件商品
    发出一件商品...
    发出一件商品...
    -------压力測试------
    投币成功
    退币成功
    您未投币,想退钱?...
    您未投币,想拿东西么?...
    您未投币,想拿东西么?...
    您未投币,想退钱?...
    

    恭喜你。又学会了一个设计模式,状态模式。最后看下状态模式的类图:


    最后,欢迎大家留言~






    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    postgresql字符串函数
    ruby中的设计模式--策略模式
    (转)MySQL 性能优化的最佳20多条经验分享
    (转)ruby中的设计模式--模板方法
    观察者模式的应用
    postgresql的ARRAY_TO_STRING
    ruby和javascript的观察者模式
    mysql表连接的时候注意事项
    checkbox记忆功能的实现
    order by的注意事项
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4644532.html
Copyright © 2020-2023  润新知