Java设计模式之状态模式State Pattern详解

目录
  • 概述
  • UML类图
  • 状态模式与策略模式
  • 谁决定状态转换的流向
  • State是接口还是抽象类
  • 应用案例分析
    • 状态抽象类
    • 可以抽奖的状态
    • 奖品发放完毕状态
    • 发放奖品的状态
    • 不能抽奖状态
    • 抽奖活动(Context)
    • 测试状态模式

概述

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。这个模式将状态封装成独立的类,并将动作委托到 代表当前状态的对象,我们知道行为会随着内部状态而改变。

一个对象“看起来好像修改了它的类”是什么意思呢?从客户的视角来看:如果说你使用的对象能够完全改变它的行为,那么你会觉得,这个对象实际上是从别的类实例化而来的。然而,实际上,你知道我们是在使用组合通过简单引用不同的状态对象来造成类改变的假象。

状态模式它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换。

UML类图

  • Context是一个类,它可以拥有一些内部状态。
  • State接口定义了一个所有具体状态的共同接口,任何状态都实现这个相同的接口,这样一来状态之间可以互相替换。
  • 不管在什么时候,只要有人调用Context的request()方法,它就会被委托到状态来处理。
  • ConcreteState处理来自Context的请求。每一个ConcreteState都提供了它自己对于请求的实现。所以,当Context改变状态时,行为也跟着改变。

状态模式与策略模式

以状态模式而言,我们将一群行为封装在状态对象中,context的行为随时可委托到那些状态对象中的一个。随着时间的流逝,当前状态在状态对象集合中游走改变,以反映出context内部的状态,因此context的行为也会随着改变。但是context的客户对于状态对象了解不多,甚至根本是浑然不觉。

而以策略模式而言,客户通常主动指定Context所要组合的策略对象是哪一个。现在,固然策略模式让我们具有弹性,能够在运行时改变策略,但对于某个context对象来说,通常都只有一个最适当的策略对象。

一般来说,我们把策略模式想成是除了继承之外的一种弹性替代方案。如果你使用继承定义了一个类的行为,你将被这个行为困住,甚至要修改它都很难。有了策略模式,你可以通过组合不同的对象来改变行为。

我们把状态模式想成是不用在context中放置许多条件判断的替代方案。通过将行为包装进状态对象中,你可以通过在context内见到地改变状态对象来改变context的行为。

谁决定状态转换的流向

Context或者ConcreteState都可以。

一般来讲,当状态转换是固定的时候,就适合放在Context中。然而,当转换是动态的时候,通常就会放在状态类中。

将状态放在状态类中的缺点是:状态类之间产生了依赖。

State是接口还是抽象类

答:都可以。如果我们没有共同的功能可以放进抽象类中,就会使用接口。在你实现状态模式时,很可能想使用抽象类。这么一来,当你以后需要在抽象类中加入新的方法是就很容易,不需要打破具体状态的实现。

应用案例分析

请编写程序完成APP 抽奖活动具体要求如下:

  • 假如每参加一次这个活动要扣除用户50 积分,中奖概率是10%
  • 奖品数量固定,抽完就不能抽奖
  • 活动有四个状态: 可以抽奖、不能抽奖、发放奖品和奖品领完
  • 活动的四个状态转换关系图

那么需要如何做呢?

  • 定义出一个接口(或抽象类)叫状态接口,每个状态都实现(继承)它。
  • 接口有扣除积分方法、抽奖方法、发放奖品方法

状态抽象类

/**
 * 状态抽象类
 */
public abstract class State {
	// 扣除积分 - 50
    public abstract void deductMoney();
    // 是否抽中奖品
    public abstract boolean raffle();
    // 发放奖品
    public abstract  void dispensePrize();
}

可以抽奖的状态

public class CanRaffleState extends State {
    RaffleActivity activity;
    public CanRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }
    //已经扣除了积分,不能再扣
    @Override
    public void deductMoney() {
        System.out.println("已经扣取过了积分");
    }
    //可以抽奖, 抽完奖后,根据实际情况,改成新的状态
    @Override
    public boolean raffle() {
        System.out.println("正在抽奖,请稍等!");
        Random r = new Random();
        int num = r.nextInt(10);
        // 10%中奖机会
        if(num == 0){
            // 改变活动状态为发放奖品 context
            activity.setState(activity.getDispenseState());
            return true;
        }else{
            System.out.println("很遗憾没有抽中奖品!");
            // 改变状态为不能抽奖
            activity.setState(activity.getNoRafflleState());
            return false;
        }
    }
    // 不能发放奖品
    @Override
    public void dispensePrize() {
        System.out.println("没中奖,不能发放奖品");
    }
}

奖品发放完毕状态

/**
 * 奖品发放完毕状态
 * 说明,当我们activity 改变成 DispenseOutState, 抽奖活动结束
 */
public class DispenseOutState extends State {
	// 初始化时传入活动引用
    RaffleActivity activity;

    public DispenseOutState(RaffleActivity activity) {
        this.activity = activity;
    }
    @Override
    public void deductMoney() {
        System.out.println("奖品发送完了,请下次再参加");
    }
    @Override
    public boolean raffle() {
        System.out.println("奖品发送完了,请下次再参加");
        return false;
    }
    @Override
    public void dispensePrize() {
        System.out.println("奖品发送完了,请下次再参加");
    }
}

发放奖品的状态

public class DispenseState extends State {
	 // 初始化时传入活动引用,发放奖品后改变其状态
    RaffleActivity activity;
    public DispenseState(RaffleActivity activity) {
        this.activity = activity;
    }
    @Override
    public void deductMoney() {
        System.out.println("不能扣除积分");
    }
    @Override
    public boolean raffle() {
        System.out.println("不能抽奖");
        return false;
    }
    //发放奖品
    @Override
    public 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);
        }
    }
}

不能抽奖状态

public class NoRaffleState extends State {
	 // 初始化时传入活动引用,扣除积分后改变其状态
    RaffleActivity activity;
    public NoRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }
    // 当前状态可以扣积分 , 扣除后,将状态设置成可以抽奖状态
    @Override
    public void deductMoney() {
        System.out.println("扣除50积分成功,您可以抽奖了");
        activity.setState(activity.getCanRaffleState());
    }
    // 当前状态不能抽奖
    @Override
    public boolean raffle() {
        System.out.println("扣了积分才能抽奖喔!");
        return false;
    }
    // 当前状态不能发奖品
    @Override
    public void dispensePrize() {
        System.out.println("不能发放奖品");
    }
}

抽奖活动(Context)

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;
    }
    //扣分, 调用当前状态的 deductMoney
    public 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;
    }
}

测试状态模式

public class ClientTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 创建活动对象,奖品有1个奖品
        RaffleActivity activity = new RaffleActivity(1);
        // 我们连续抽300次奖
        for (int i = 0; i < 30; i++) {
            System.out.println("--------第" + (i + 1) + "次抽奖----------");
            // 参加抽奖,第一步点击扣除积分
            activity.debuctMoney();
            // 第二步抽奖
            activity.raffle();
        }
	}
}

UML类图如下:

到此这篇关于Java设计模式之状态模式State Pattern详解的文章就介绍到这了,更多相关Java状态模式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 轻松掌握Java状态模式

    定义:在状态模式(State Pattern)中,类的行为是基于它的状态改变的. 特点: 1.封装了转换规则. 2.枚举可能的状态,在枚举状态之前需要确定状态种类. 3.将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为. 4.允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块. 5.可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数. 企业及开发和常用框架中的应用: 实例: public class Demo { p

  • Java设计模式之java状态模式详解

    目录 状态模式的结构 状态模式的角色 示例代码 适用场景 投票案例 认识状态模式 状态和行为 行为的平行性 环境和状态处理对象 状态模式优点 状态模式的缺点 状态模式和策略模式对比 参考文章 总结 状态模式的结构 用一句话来表述,状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类.状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变.状态模式的示意性类图如下所示: 状态模式的角色 环境(Context)角色,也成上下文:定义客户端所感兴

  • Java设计模式之状态模式

    实际开发中订单往往都包含着订单状态,用户每进行一次操作都要切换对应的状态,而每次切换判断当前的状态是必须的,就不可避免的引入一系列判断语句,为了让代码更加清晰直观,我们引入今天的主角——状态模式. 一.概念理解 假设订单状态有,下单.发货.确认收货,如果用户确认收货,在常规编程中就要判断当前用户的状态,然后再修改状态,如果这种情况下使用状态模式. 将各个状态都抽象成一个状态类,比如下单状态类.发货状态类.确认收货类,在状态类中处理相应的逻辑和控制下一个状态,在定义一个环境类,定义初始状态,并控制

  • Java基于状态模式实现的文档编辑模式切换功能实例

    本文实例讲述了Java基于状态模式实现的文档编辑模式切换功能.分享给大家供大家参考,具体如下: 一 模式定义 状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来就像是改变了其类. 二 模式举例 1 模式分析 我们借用文档编辑模式切换这一案例来说明这一模式. 2 状态模式静态类图 3 代码示例 3.1 创建状态接口一IState package com.demo.state; import com.demo.context.Context; /** * * 状态接口 * * @au

  • 详解JAVA 设计模式之状态模式

    在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式. 在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象. 介绍 意图: 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类. 主要解决: 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为. 何时使用: 代码中包含大量与对象状态有关的条件语句. 如何解决: 将各种具体的状态类抽象出来. 关键代码: 通常

  • 23种设计模式(22)java状态模式

    一.概述 当系统中某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式.状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化.状态模式是一种对象行为型模式. 二.适用场景 用于解决系统中复杂对象的多种状态转换以及不同状态下行为的封装问题.简单说就是处理对象的多种状态及其相互转换. 三.UML类图 四.参与者 1).AbstractState(抽象状态类): 在抽象状态类中定义申明了不同状态下的行为抽象方法,而由子类

  • Java设计模式之状态模式(State模式)介绍

    State的定义:不同的状态,不同的行为:或者说,每个状态有着相应的行为. 何时使用状态模式 State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了. 不只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,用以标识记录中一些特殊

  • 深入理解Java设计模式之状态模式

    目录 一.什么是状态模式 二.状态模式的结构 三.状态模式的使用场景 四.状态模式和策略模式对比 五.状态模式的优缺点 六.状态模式的实现 七.总结 一.什么是状态模式 定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 主要解决:当控制一个对象状态的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化. 意图:允许一个对象在其内部状态改变时改变它的行为 二.状态模式的结构 在该类图中,我们看到三个角色: (1)Cont

  • Java设计模式之状态模式State Pattern详解

    目录 概述 UML类图 状态模式与策略模式 谁决定状态转换的流向 State是接口还是抽象类 应用案例分析 状态抽象类 可以抽奖的状态 奖品发放完毕状态 发放奖品的状态 不能抽奖状态 抽奖活动(Context) 测试状态模式 概述 状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类.这个模式将状态封装成独立的类,并将动作委托到 代表当前状态的对象,我们知道行为会随着内部状态而改变. 一个对象“看起来好像修改了它的类”是什么意思呢?从客户的视角来看:如果说你使用的对象能够完全

  • Java如何利用状态模式(state pattern)替代if else

    大多数开发人员现在还在使用if else的过程结构,曾看过jdon的banq大哥写的一篇文章,利用command,aop模式替代if else过程结构.当时还不太明白,这几天看了<重构>第一章的影片租赁案例,感触颇深.下面我来谈一谈为什么要用state pattern替代if else,替代if else有什么好处,以及给出详细代码怎么替代if else.本文参考jdon的"你还在使用if else吗?"及<重构>第一章. 首先我们模仿影片租赁过程,顾客租凭影片

  • Java设计模式之建造者模式的示例详解

    目录 定义 案例 需求 方案一 方案二 对比分析 总结 建造者模式的优势: 注意点 定义 建造者模式(Builder Pattern),又叫生成器模式,是一种对象构建模式 它可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现的对象.建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可 以构建它们,用户不需要知道内部的具体构建细节. 案例 需求 女生每天化妆,假如只需要做发型,香水,衣服,并要求按照发型——>香水——>衣服的顺序进行,

  • java设计模式责任链模式原理案例详解

    目录 引言 责任链模式定义 类图 角色 核心 示例代码 1.对请求处理者的抽象 2.对请求处理者的抽象 3.责任链的创建 责任链实现请假案例 案例类图 可扩展性 纯与不纯的责任链模式 纯的责任链模式 不纯的责任链模式 责任链模式主要优点 职责链模式的主要缺点 适用场景 模拟实现Tomcat中的过滤器机制 运行过程如下 分析Tomcat 过滤器中的责任链模式 引言 以请假流程为例,一般公司普通员工的请假流程简化如下: 普通员工发起一个请假申请,当请假天数小于3天时只需要得到主管批准即可:当请假天数

  • Java设计模式之原型模式的示例详解

    目录 定义 案例 需求 方案一 方案二 对比分析 总结 定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 即实现了一个原型接口,该接口用于创建当前对象的克隆,当直接创建对象的代价比较大时,则采用这种模式 案例 需求 张三要打印100000份照片 方案一 定义照片类 /** * 照片类 * @author:liyajie * @createTime:2022/2/15 11:47 * @version:1.0 */ @Data @AllArgsConstructor publi

  • Java设计模式之桥接模式的示例详解

    目录 定义 案例 需求 方案一 方案二 对比分析 总结 定义 桥梁模式是对象的结构模式.又称为柄体(Handle and Body)模式或接口(Interface)模式.桥梁模式的用意是“将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化”. 案例 需求 通过企业微信和qq的方式给员工发送消息 方案一 定义发送消息的接口 /** * 发送消息的接口 * @author:liyajie * @createTime:2022/2/21 10:33

  • Java设计模式之组合模式的示例详解

    目录 定义 原理类图 案例 需求 方案 分析 总结 定义 组合模式,又叫部分整体模式,它创建了对象组的数据结构(将对象组合成树状结构,用来表示部分整体的层级关系)组合模式使得用户对单个对象和组合对象的访问具有一致性 原理类图 Component :这是组合模式中的抽象构件,他里面定义了所有类共有的默认行为,用来访问和管理Component的子部件,Component可以是抽象类,也可以是接口 leaf :在组合模式中表示叶子节点,叶子节点没有子节点了,他是最末端存放数据的结构 Composite

  • Java设计模式之工厂模式实现方法详解

    本文实例讲述了Java设计模式之工厂模式实现方法.分享给大家供大家参考,具体如下: 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的 工厂模式在分为三类: 1)简单工厂模式(Simple Factory):不利于产生系列产品: 2)工厂方法模式(Factory Method):又称为多形性工厂: 3)抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品: 一.简单工厂模式 简单工厂模式又称静态工厂方法模式

  • java 设计模式(DAO)的实例详解

    java 设计模式(DAO)的实例详解 应用场景:在Java程序中,经常需要把数据持久化,也需要获取持久化的数据,但是在进行数据持久化的过程中面临诸多问题(如:数据源不同.存储类型不同.供应商不同.访问方式不同等等),请问如何能以统一的接口进行数据持久化的操作? 其实这个我没学号(≧ ﹏ ≦).我的理解就是一个产品面向的用户不是单一的,所以我们要兼容许多情况如前面提到的数据源不同.存储类型不同.供应商不同.访问方式不同等等. ★ 解决方案 DAO的理解: 1.DAO其实是利用组合工厂模式来解决问

随机推荐