热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

设计模式学习(二十)状态模式

文章目录状态模式基本介绍应用举例总结状态模式基本介绍状态模式(StatePattern):它主要用来解决对象在多种状态转换时ÿ

文章目录

  • 状态模式
    • 基本介绍
    • 应用举例
    • 总结


状态模式

基本介绍


  • 状态模式( State Pattern ):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换
  • 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类
  • 类图:
    在这里插入图片描述
    • Context 类为环境角色 , 用于维护 State 实例这个实例定义当前状态
    • State 是抽象状态角色定义一个接口封装与 Context 的一个特点接口相关行为
    • ConcreteState 具体的状态角色,每个子类实现一个与 Context 的一个状态相关行为

应用举例


  • 用一个应用来举例:
    在这里插入图片描述

  • 类图:
    在这里插入图片描述

  • 代码实现:

/*** 状态抽象类* @author Administrator**/
public abstract class State {// 扣除积分 - 50public abstract void deductMoney();// 是否抽中奖品public abstract boolean raffle();// 发放奖品public abstract void dispensePrize();}
/*** 不能抽奖状态* @author Administrator**/
public class NoRaffleState extends State {// 初始化时传入活动引用,扣除积分后改变其状态RaffleActivity activity;public NoRaffleState(RaffleActivity activity) {this.activity = activity;}// 当前状态可以扣积分 , 扣除后,将状态设置成可以抽奖状态@Overridepublic void deductMoney() {System.out.println("扣除50积分成功,您可以抽奖了");activity.setState(activity.getCanRaffleState());}// 当前状态不能抽奖@Overridepublic boolean raffle() {System.out.println("扣了积分才能抽奖喔!");return false;}// 当前状态不能发奖品@Overridepublic void dispensePrize() {System.out.println("不能发放奖品");}
}
/*** 可以抽奖的状态* @author Administrator**/
public class CanRaffleState extends State {RaffleActivity activity;public CanRaffleState(RaffleActivity activity) {this.activity = activity;}//已经扣除了积分,不能再扣@Overridepublic void deductMoney() {System.out.println("已经扣取过了积分");}//可以抽奖, 抽完奖后,根据实际情况,改成新的状态@Overridepublic boolean raffle() {System.out.println("正在抽奖,请稍等!");Random r = new Random();int num = r.nextInt(10);// 10%中奖机会if(num == 0){// 改变活动状态为发放奖品 contextactivity.setState(activity.getDispenseState());return true;}else{System.out.println("很遗憾没有抽中奖品!");// 改变状态为不能抽奖activity.setState(activity.getNoRafflleState());return false;}}// 不能发放奖品@Overridepublic void dispensePrize() {System.out.println("没中奖,不能发放奖品");}
}
/*** 发放奖品的状态* @author Administrator**/
public class DispenseState extends State {// 初始化时传入活动引用,发放奖品后改变其状态RaffleActivity activity;public DispenseState(RaffleActivity activity) {this.activity = activity;}//@Overridepublic void deductMoney() {System.out.println("不能扣除积分");}@Overridepublic boolean raffle() {System.out.println("不能抽奖");return false;}//发放奖品@Overridepublic void dispensePrize() {if(activity.getCount() > 0){System.out.println("恭喜中奖了");// 改变状态为不能抽奖activity.setState(activity.getNoRafflleState());}else{System.out.println("很遗憾,奖品发送完了");// 改变状态为奖品发送完毕, 后面我们就不可以抽奖activity.setState(activity.getDispensOutState());//System.out.println("抽奖活动结束");//System.exit(0);}}
}
/*** 奖品发放完毕状态* 说明,当我们activity 改变成 DispenseOutState, 抽奖活动结束* @author Administrator**/
public class DispenseOutState extends State {// 初始化时传入活动引用RaffleActivity activity;public DispenseOutState(RaffleActivity activity) {this.activity = activity;}@Overridepublic void deductMoney() {System.out.println("奖品发送完了,请下次再参加");}@Overridepublic boolean raffle() {System.out.println("奖品发送完了,请下次再参加");return false;}@Overridepublic void dispensePrize() {System.out.println("奖品发送完了,请下次再参加");}
}
/*** 抽奖活动 //* * @author Administrator**/
public class RaffleActivity {// state 表示活动当前的状态,是变化State state = null;// 奖品数量int count = 0;// 四个属性,表示四种状态State noRafflleState = new NoRaffleState(this);State canRaffleState = new CanRaffleState(this);State dispenseState = new DispenseState(this);State dispensOutState = new DispenseOutState(this);//构造器//1. 初始化当前的状态为 noRafflleState(即不能抽奖的状态)//2. 初始化奖品的数量 public RaffleActivity( int count) {this.state = getNoRafflleState();this.count = count;}//扣分, 调用当前状态的 deductMoneypublic void debuctMoney(){state.deductMoney();}//抽奖 public void raffle(){// 如果当前的状态是抽奖成功if(state.raffle()){//领取奖品state.dispensePrize();}}public State getState() {return state;}public void setState(State state) {this.state = state;}//这里请大家注意,每领取一次奖品,count--public int getCount() {int curCount = count; count--;return curCount;}public void setCount(int count) {this.count = count;}public State getNoRafflleState() {return noRafflleState;}public void setNoRafflleState(State noRafflleState) {this.noRafflleState = noRafflleState;}public State getCanRaffleState() {return canRaffleState;}public void setCanRaffleState(State canRaffleState) {this.canRaffleState = canRaffleState;}public State getDispenseState() {return dispenseState;}public void setDispenseState(State dispenseState) {this.dispenseState = dispenseState;}public State getDispensOutState() {return dispensOutState;}public void setDispensOutState(State dispensOutState) {this.dispensOutState = dispensOutState;}
}
/*** 状态模式测试类* @author Administrator**/
public class ClientTest {public static void main(String[] args) {// TODO Auto-generated method stub// 创建活动对象&#xff0c;奖品有1个奖品RaffleActivity activity &#61; new RaffleActivity(1);// 我们连续抽300次奖for (int i &#61; 0; i < 30; i&#43;&#43;) {System.out.println("--------第" &#43; (i &#43; 1) &#43; "次抽奖----------");// 参加抽奖&#xff0c;第一步点击扣除积分activity.debuctMoney();// 第二步抽奖activity.raffle();}}}

  • 结果&#xff1a;
    在这里插入图片描述
    在这里插入图片描述

总结


  • 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中。
  • 方便维护&#xff1a;将容易产生问题的 if else 语句删除了&#xff0c;如果把每个状态的行为都放到一个类中&#xff0c;每次调用方法时都要判断当前是什么状态&#xff0c;不但会产出很多 if else 语句&#xff0c;而且容易出错。
  • 符合“开闭原则”。容易增删状态。
  • 会产生很多类。每个状态都要一个对应的类&#xff0c;当状态过多时会产生很多类&#xff0c;加大维护难度。
    应用场景&#xff1a;当一个事件或者对象有很多种状态&#xff0c;状态之间会相互转换&#xff0c;对不同的状态要求有不同的行为的时候&#xff0c;可以考虑使用状态模式。

推荐阅读
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 摘要: 在测试数据中,生成中文姓名是一个常见的需求。本文介绍了使用C#编写的随机生成中文姓名的方法,并分享了相关代码。作者欢迎读者提出意见和建议。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
author-avatar
n张家珲
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有