转载请注明出处: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. 自己定义 ViewGroup 支持无限循环翻页之三(响应回调事件)

    大家假设喜欢我的博客,请关注一下我的微博,请点击这里(http://weibo.com/kifile),谢谢 转载请标明出处,再次感谢 ################################ ...

  2. Java重写方法与初始化的隐患(转)

    原文出处: Shawon 虽然文章标题是Java, 但几乎所有面向对象设计的语言都遵守这个初始化流程, 感谢廖祜秋liaohuqiu_秋百万指出, 之前忘记提这个了. 前言 drakeet写了个和Re ...

  3. linuxserver启动过程

    随着Linux的应用日益广泛.特别是在网络应用方面,有大量的网络server使用Linux操作系统.因为Linux的桌面应用和Windows相比另一 定的差距.所以在企业应用中往往是Linux和Win ...

  4. unity3d由于Camera.main.transform报空引用错误的解决方案

    今天在导入character包后,引用了内置的第三人称素材,但是在启动的时候程序报空引用的错误: 引起错误的位置在: 错误原因是因为没有将摄像机的tag设置为maincamera,改为maincame ...

  5. cocos2d-x 2.2.3 创建项目的方法

    直接复制粘贴到txt文本,然后修改后缀为.bat,然后将bat文件放到tools\project-creator的目录下即可. :project_input @echo 请输入项目名称,按回车,例:H ...

  6. 【前端攻略】:玩转图片Base64编码(转)

    引言 图片处理在前端工作中可谓占据了很重要的一壁江山.而图片的Base64编码可能相对一些人而言比较陌生,本文不是从纯技术的角度去讨论图片的base64编码.标题略大,不过只是希望通过一些浅显的论述, ...

  7. jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令

    jstack(查看线程).jmap(查看内存)和jstat(性能分析)命令   公司内部同事分享的一篇文章 周末看到一个用jstack查看死锁的例子.昨天晚上总结了一下jstack(查看线程).jma ...

  8. struts2集成fckeditor(来自大型门户网站是这样练成的一书)

  9. c# 通过解析mp3规范命名并上传服务器

    引用using Shell32; private void Open_Click(object sender, RoutedEventArgs e) { OpenFileDialog ofd = ne ...

  10. Web Worker在WebKit中的实现机制

    web worker 是执行在后台的 JavaScript,独立于其它脚本.不会影响页面的性能.这是HTML5的一个标准:实现上讲.浏览器为wokrer启动了新的线程,从而实现了异步操作的功能; 以下 ...