转载请注明出处: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件商品
发出一件商品...
发出一件商品...
-------压力測试------
投币成功
退币成功
您未投币,想退钱?...
您未投币,想拿东西么?...
您未投币,想拿东西么?...
您未投币,想退钱?...

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG1qNjIzNTY1Nzkx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

最后,欢迎大家留言~

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

设计模式 State模式 机器的情况下用自己的主动性的更多相关文章

  1. java设计模式-State模式

    1.背景: MM的状态是非常不固定的,说不定刚才还非常高兴,没准一会就生气了.就跟六月的天似的,说变就变. 封装一下MM的状态:smile,cry,say:MM的状态决定了这些方法该怎么执行.   2 ...

  2. [Design Pattern With Go]设计模式-工厂模式

    这次介绍的设计模式是工厂模式,这是一个比较常见的创建型模式.一般情况下,工厂模式分为三种:简单工厂.工厂方法和抽象工厂,下面慢慢举例介绍下. 简单工厂 考虑一个加密程序的应用场景,一个加密程序可能提供 ...

  3. 'adb remount'的作用是什么?在什么情况下有用?

    'adb remount' 将 '/system' 部分置于可写入的模式,默认情况下 '/system' 部分是只读模式的.这个命令只适用于已被 root 的设备. 在将文件 push 到 '/sys ...

  4. 如何处理高并发情况下的DB插入

    1.  我们需要接收一个外部的订单,而这个订单号是不允许重复的 2.  数据库对外部订单号没有做唯一性约束 3.  外部经常插入相同的订单,对于已经存在的订单则拒绝处理 对于这个需求,很简单我们会用下 ...

  5. 深入浅出设计模式——状态模式(State Pattern)

    模式动机 在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的 (stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的.当一个这样的 ...

  6. 设计模式---状态变化模式之state状态模式(State)

    前提:状态变化模式 在组建构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?“状态变化”模式为这一个问题提供了一种解决方案. 典型模式 状态模式:Stat ...

  7. java 23种设计模式,一般情况下,常用的有哪些? 转载

    原址:http://wangle.iteye.com/blog/196972 工厂模式, 工厂方法模式,单例模式, 外观(Facade)模式, 观察者(Observer)模式,桥接(Bridge)模式 ...

  8. C++设计模式之State模式

    这里有两个例子: 1.https://www.cnblogs.com/wanggary/archive/2011/04/21/2024117.html 2.https://www.cnblogs.co ...

  9. 程序设计模式 —— State 状态模式

    我应该如何阅读? 本文将使用优雅的文字风格来告诉你什么是状态模式. 注意: 1.在阅读本文之前请保证你已经掌控了 面对对象的思想与 多态的基本概念,否则将难以理解. 2.本文实现将用C++实现,你不一 ...

随机推荐

  1. POJ 3632 Optimal Parking(简单题)

    [题意简述]:就是选择一个停车地点.然后走遍全部的store后,再回到停车地点.就是走一圈.问要走的距离是多少. [分析]:能够直接求出距离的最大值与最小值,求出差值.乘以2就是最后的输出结果. // ...

  2. 内存分析工具 MAT 的使用

    1 内存泄漏的排查方法 Dalvik Debug Monitor Server (DDMS) 是 ADT插件的一部分,当中有两项功能可用于内存检查 : ·    heap 查看堆的分配情况 ·     ...

  3. cocos2dx 3.1从零学习(六)——CocosStudio(VS2013project导入及环境设置)

    导入libCocosStudio.libExtensions.libGUI 新建的project例如以下图: 加入现有项目 右键解决方式.例如以下操作: watermark/2/text/aHR0cD ...

  4. 基于HttpClient 4.3的可訪问自签名HTTPS网站的新版工具类

    本文出处:http://blog.csdn.net/chaijunkun/article/details/40145685,转载请注明.因为本人不定期会整理相关博文,会对相应内容作出完好.因此强烈建议 ...

  5. PyUnit框架学习

    http://www.oschina.net/question/12_27127#INSTALL http://www.360doc.com/content/11/0606/23/54470_1221 ...

  6. iOS游戏开发游戏功能之外的东西

    对于一个游戏的开发,我们除了完毕游戏的功能之外,还有多少东西我们须要考虑呢? 非常多.也非常烦! 但做过一遍之后下一次就会非常easy. 都有什么东西我们想加入到游戏其中呢? (1)分享功能 (2)评 ...

  7. centos 安装 使用本地图像文件来安装网络安装

    有时很无奈,无盘,U它只有盘4G而一个centos该盘4.16G,如何将它安装了网络安装,对不起,你想用20M更多的带宽,并注意使用网络启动盘的方法 没有条件,应该创造条件: 网络安装,需要下载图片, ...

  8. KMP算法---字符串匹配

    算法细节详见点击打开链接和点击打开链接 #include <stdio.h> #include <stdlib.h> #define N 7 #define M 15 void ...

  9. Linux下一个C(编程入门.h档,.c档,而路多文件的调用)

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcXVhbg==/font/5a6L5L2T/fontsize/400/fill/I0 ...

  10. 工作经常使用的SQL整理,实战篇(二)

    原文:工作经常使用的SQL整理,实战篇(二) 工作经常使用的SQL整理,实战篇,地址一览: 工作经常使用的SQL整理,实战篇(一) 工作经常使用的SQL整理,实战篇(二) 工作经常使用的SQL整理,实 ...