18.2 解决方案
18.2.1 状态模式来解决
用来解决上述问题的一个合理的解决方案就是状态模式。那么什么是状态模式呢?
(1)状态模式定义
(2)应用状态模式来解决的思路
仔细分析上面的问题,会发现,那几种用户投票的类型,就相当于是描述了人员的几种投票状态,而各个状态和对应的功能处理具有很强的对应性,有点类似于“一个萝卜一个坑”,各个状态下的处理基本上都是不一样的,也不存在可以相互替换的可能。
为了解决上面提出的问题,很自然的一个设计就是首先把状态和状态对应的行为从原来的大杂烩代码中分离出来,把每个状态所对应的功能处理封装在一个独立的类里面,这样选择不同处理的时候,其实就是在选择不同的状态处理类。
然后为了统一操作这些不同的状态类,定义一个状态接口来约束它们,这样外部就可以面向这个统一的状态接口编程,而无需关心具体的状态类实现了。
这样一来,要修改某种投票情况所对应的具体功能处理,那就是直接修改或者扩展某个状态处理类的功能就可以了。而要添加新的功能就更简单,直接添加新的状态处理类就可以了,当然在使用Context的时候,需要设置使用这个新的状态类的实例。
18.2.2 模式结构和说明
状态模式的结构如图18.1所示:
图18.1 状态模式结构示意图
Context:
环境,也称上下文,通常用来定义客户感兴趣的接口,同时维护一个来具体处理当前状态的实例对象。
State:
状态接口,用来封装与上下文的一个特定状态所对应的行为。
ConcreteState:
具体实现状态处理的类,每个类实现一个跟上下文相关的状态的具体处理。
18.2.3 状态模式示例代码
(1)首先来看状态接口,示例代码如下:
/** * 封装与Context的一个特定状态相关的行为 */ public interface State { /** * 状态对应的处理 * @param sampleParameter 示例参数,说明可以传入参数,具体传入 * 什么样的参数,传入几个参数,由具体应用来具体分析 */ public void handle(String sampleParameter); } |
(2)再来看看具体的状态实现,目前具体的实现ConcreteStateA和ConcreteStateB示范的是一样的,只是名称不同,示例代码如下:
/** * 实现一个与Context的一个特定状态相关的行为 */ public class ConcreteStateA implements State { public void handle(String sampleParameter) { //实现具体的处理 } } |
/** * 实现一个与Context的一个特定状态相关的行为 */ public class ConcreteStateB implements State { public void handle(String sampleParameter) { //实现具体的处理 } } |
(3)再来看看上下文的具体实现,上下文通常用来定义客户感兴趣的接口,同时维护一个具体的处理当前状态的实例对象。示例代码如下:
/** * 定义客户感兴趣的接口,通常会维护一个State类型的对象实例 */ public class Context { /** * 持有一个State类型的对象实例 */ private State state; /** * 设置实现State的对象的实例 * @param state 实现State的对象的实例 */ public void setState(State state) { this.state = state; } /** * 用户感兴趣的接口方法 * @param sampleParameter 示意参数 */ public void request(String sampleParameter) { //在处理中,会转调state来处理 state.handle(sampleParameter); } } |
18.2.4 使用状态模式重写示例
看完了上面的状态模式的知识,有些朋友跃跃欲试,打算使用状态模式来重写前面的示例,要使用状态模式,首先就需要把投票过程的各种状态定义出来,然后把这些状态对应的处理从原来大杂烩的实现中分离出来,形成独立的状态处理对象。而原来的投票管理的对象就相当于Context了。
把状态对应的行为分离出去过后,怎么调用呢?
按照状态模式的示例,是在Context中,处理客户请求的时候,转调相应的状态对应的具体的状态处理类来进行处理。
那就引出下一个问题:那么这些状态怎么变化呢?
看原来的实现,就是在投票方法里面,根据投票的次数进行判断,并维护投票类型的变化。那好,也依葫芦画瓢,就在投票方法里面来维护状态变化。
这个时候的程序结构如图18.2所示:
图18.2 状态模式的示例程序机构示意图
(1)先来看状态接口的代码实现,示例代码如下:
/** * 封装一个投票状态相关的行为 */ public interface VoteState { /** * 处理状态对应的行为 * @param user 投票人 * @param voteItem 投票项 * @param voteManager 投票上下文,用来在实现状态对应的功能处理的时候, * 可以回调上下文的数据 */ public void vote(String user,String voteItem ,VoteManager voteManager); } |
(2)定义了状态接口,那就该来看看如何实现各个状态对应的处理了,现在的实现很简单,就是把原来的实现从投票管理类里面分离出来就可以了。先看正常投票状态对应的处理,示例代码如下:
public class NormalVoteState implements VoteState{ public void vote(String user, String voteItem ,VoteManager voteManager) { //正常投票 //记录到投票记录中 voteManager.getMapVote().put(user, voteItem); System.out.println("恭喜你投票成功"); } } |
接下来看看重复投票状态对应的处理,示例代码如下:
public class RepeatVoteState implements VoteState{ public void vote(String user, String voteItem ,VoteManager voteManager) { //重复投票 //暂时不做处理 System.out.println("请不要重复投票"); } } |
接下来看看恶意投票状态对应的处理,示例代码如下:
public class SpiteVoteState implements VoteState{ public void vote(String user, String voteItem ,VoteManager voteManager) { //恶意投票 //取消用户的投票资格,并取消投票记录 String s = voteManager.getMapVote().get(user); if(s!=null){ voteManager.getMapVote().remove(user); } System.out.println("你有恶意刷票行为,取消投票资格"); } } |
接下来看看黑名单状态对应的处理,示例代码如下:
public class BlackVoteState implements VoteState{ public void vote(String user, String voteItem ,VoteManager voteManager) { //黑名单 //记入黑名单中,禁止登录系统了 System.out.println("进入黑名单,将禁止登录和使用本系统"); } } |
(3)定义好了状态接口和状态实现,看看现在的投票管理,相当于状态模式中的上下文,相对而言,它的改变如下:
- 添加持有状态处理对象
- 添加能获取记录用户投票结果的Map的方法,各个状态处理对象,在进行状态对应的处理的时候,需要获取上下文中的记录用户投票结果的Map数据
- 在vote()方法实现里面,原来判断投票类型就变成了判断投票的状态,而原来每种投票类型对应的处理,现在已经封装到对应的状态对象里面去了,因此直接转调对应的状态对象的方法即可
示例代码如下:
/** * 投票管理 */ public class VoteManager { /** * 持有状态处理对象 */ private VoteState state = null; /** * 记录用户投票的结果,Map<String,String>对应Map<用户名称,投票的选项> */ private Map<String,String> mapVote = new HashMap<String,String>(); /** * 记录用户投票次数,Map<String,Integer>对应Map<用户名称,投票的次数> */ private Map<String,Integer> mapVoteCount = new HashMap<String,Integer>(); /** * 获取记录用户投票结果的Map * @return 记录用户投票结果的Map */ public Map<String, String> getMapVote() { return mapVote; }
/** * 投票 * @param user 投票人,为了简单,就是用户名称 * @param voteItem 投票的选项 */ public void vote(String user,String voteItem){ //1:先为该用户增加投票的次数 //先从记录中取出已有的投票次数 Integer oldVoteCount = mapVoteCount.get(user); if(oldVoteCount==null){ oldVoteCount = 0; } oldVoteCount = oldVoteCount + 1; mapVoteCount.put(user, oldVoteCount); //2:判断该用户投票的类型,就相当于是判断对应的状态 //到底是正常投票、重复投票、恶意投票还是上黑名单的状态 if(oldVoteCount==1){ state = new NormalVoteState(); }else if(oldVoteCount>1 && oldVoteCount<5){ state = new RepeatVoteState(); }else if(oldVoteCount >= 5 && oldVoteCount<8){ state = new SpiteVoteState(); }else if(oldVoteCount>=8){ state = new BlackVoteState(); }
//然后转调状态对象来进行相应的操作 state.vote(user, voteItem, this); } } |
(4)该写个客户端来测试一下了,经过这么修改过后,好用吗?试试看就知道了。客户端没有任何的改变,跟前面实现的一样,示例代码如下:
public class Client { public static void main(String[] args) { VoteManager vm = new VoteManager(); for(int i=0;i<8;i++){ vm.vote("u1", "A"); } } } |
运行一下试试吧,结果应该是跟前面一样的,也就是说都是实现一样的功能,只是采用了状态模式来实现。测试结果如下:
恭喜你投票成功 请不要重复投票 请不要重复投票 请不要重复投票 你有恶意刷票行为,取消投票资格 你有恶意刷票行为,取消投票资格 你有恶意刷票行为,取消投票资格 进入黑名单,将禁止登录和使用本系统 |
从上面的示例可以看出,状态的转换基本上都是内部行为,主要在状态模式内部来维护。比如对于投票的人员,任何时候他的操作都是投票,但是投票管理对象的处理却不一定一样,会根据投票的次数来判断状态,然后根据状态去选择不同的处理。
ps:转载私塾在线
相关推荐
- **状态模式2(面向过程的方式-方法版)**:这可能是一种非面向对象的实现,使用函数而不是类来表示状态,通过函数指针或者装饰器来改变对象的行为。 - **状态模式3(分类版)**:可能利用了Python的元类(meta...
Java 设计模式之策略模式与状态模式 策略模式是 Java 中的一种设计模式,它主要用于解决系统与第三方接口进行数据交互的问题。当系统需要与多种格式的数据进行交互时,使用策略模式可以很好地解决这个问题。例如,...
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。在C++中,状态模式通常通过定义一系列的类来表示各种状态,并用一个上下文类来管理这些状态的切换。下面将详细...
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,看起来好像对象改变了它的类。在Java中,状态模式通常通过定义不同的状态类和一个上下文类来实现,其中上下文类持有状态对象并调用其方法来响应...
本篇将探讨两种重要的行为设计模式:责任链模式(Chain of Responsibility Pattern)和状态模式(State Pattern)。 **责任链模式**是一种使多个对象都有机会处理请求的模式,避免请求发送者与接收者之间的耦合。在...
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式常用于处理对象的状态变化,使得代码更易于理解和维护。在这个实例中,我们将通过Java来深入理解并应用...
### 设计模式之状态模式详解 #### 一、设计模式概述 设计模式是软件工程领域的一种最佳实践,它提供了一套解决特定问题的通用方案。根据功能的不同,设计模式大致可以分为三大类:创建型模式、结构型模式以及行为型...
2. 结构清晰,状态模式将与状态相关的行为集中在一个类中,使得代码易于理解和扩展。 3. 允许状态转换逻辑与其他状态相关代码分离,提高了代码的可复用性。 缺点: 1. 状态类的数量可能会增多,如果状态非常多,...
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式常用于处理对象的状态变化,使得代码更易于理解和维护。在Java中,状态模式通常通过实现接口或者继承抽象...
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式常用于处理对象的状态转换逻辑,使代码结构更清晰,易于理解和维护。 在C++中实现状态模式,我们通常会...
状态模式状态模式状态模式状态模式状态模式状态模式
状态模式是一种行为设计模式,它使对象能够在内部状态改变时改变其行为,看起来好像改变了它的类。这种模式常用于处理对象在不同状态下表现各异的情况,避免了复杂的条件语句,提高了代码的可读性和可维护性。 在...
状态模式是一种行为设计模式,它使你能在运行时改变对象的行为。在状态模式中,一个对象的状态变化可以导致其行为的变化。这种模式常用于当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变其行为的...
状态模式是一种行为设计模式,它使你能在运行时改变对象的行为。在TCP连接中,状态模式的应用尤为常见,因为TCP连接在不同的阶段会有不同的行为,比如建立连接、数据传输、断开连接等。下面我们将详细探讨这个模式...
状态模式是一种行为设计模式,它允许对象在其内部状态改变时改变其行为,使得对象看起来好像修改了它的类。这种模式通常用于当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变来改变其行为时。在这个...
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式常用于处理对象的状态变化,并且使代码结构清晰,易于维护。 在C++中,状态模式通常包含以下几个关键...
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式常用于处理对象的状态变化,使得对象的行为与其状态紧密相关,通过改变对象的状态,来改变对象的行为。 ...
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式常用于处理对象的状态变化,并且在不同的状态下,对象的行为也相应地变化。在Java中,我们可以利用接口、...
本案例关注的是“状态模式”,这是一种行为设计模式,允许对象在其内部状态改变时改变其行为。状态模式通常用于替代复杂的条件语句(如if...else...),使得代码更加清晰和易于管理。我们以登录状态为例来深入探讨这...
状态模式在软件设计中是一种非常实用的模式,尤其是在处理具有多状态、且状态间相互转换的对象时。在《Java 23种设计模式24状态模式.pdf》中,作者通过详细的讲解和实例,深入探讨了状态模式的概念、动机、结构、...