博客
关于我
java设计模式--状态模式
阅读量:598 次
发布时间:2019-03-12

本文共 4810 字,大约阅读时间需要 16 分钟。

基本概念

状态模式,是对象的行为模式;

状态模式允许一个对象在其内部状态改变的时候改变其行为;这个对象看上去就像是改变了它的类一样;

状态模式的功能就是分离状态的行为,通过维护状态的变化,来调用不同状态对应的不同功能。也就是说,状态和行为是相关联的,它们的关系可以描述为:状态决定行为

基本结构

基本角色

  • 环境类(context:里面维护了一个具体状态的实例(AntFarmContext)
  • 抽象状态类(state):定义一个接口,封装一些特定的行为(AntFarmState)
  • 具体状态类(concreteState):每个子类实现一个与context的一个状态相关的行为(EatingState,InvistorState);

基本代码演示

场景一:在线投票系统的应用

要实现控制同一个用户只能投一票,如果一个用户反复投票,而且投票次数超过5次,则判定为恶意刷票,要取消该用户投票的资格,当然同时也要取消他所投的票;如果一个用户的投票次数超过8次,将进入黑名单,禁止再登录和使用系统;

要使用状态模式实现,首先需要把投票过程的各种状态定义出来,根据以上描述大致分为四种状态:正常投票、反复投票、恶意刷票、进入黑名单。然后创建一个投票管理对象(相当于Context);

 抽象状态类:

public interface VoteState {    public void vote(String user,String voteItem,VoteManager voteManager);}

具体状态类:

public class NormalVoteState implements VoteState {    @Override    public void vote(String user, String voteItem, VoteManager voteManager) {        voteManager.getMapVote().put(user, voteItem);        System.out.println("恭喜投票成功");    }}
public class RepeatVoteState implements VoteState {    @Override    public void vote(String user, String voteItem, VoteManager voteManager) {        System.out.println("请不要重复投票");    }}
public class SpiteVoteState implements VoteState {    @Override    public void vote(String user, String voteItem, VoteManager voteManager) {        // 恶意投票,取消用户的投票资格,并取消投票记录        String str = voteManager.getMapVote().get(user);        if(str != null){            voteManager.getMapVote().remove(user);        }        System.out.println("你有恶意刷屏行为,取消投票资格");    }}
public class BlackVoteState implements VoteState {    @Override    public void vote(String user, String voteItem, VoteManager voteManager) {        System.out.println("进入黑名单,将禁止登录和使用本系统");    }}

环境类:

public class VoteManager {    //持有状体处理对象    private VoteState state = null;    //记录用户投票的结果,Map
对应Map
<用户名称,投票的选项>
private Map
mapVote = new HashMap
(); //记录用户投票次数,Map
对应Map
<用户名称,投票的次数>
private Map
mapVoteCount = new HashMap
(); //获取用户投票结果的Map public Map
getMapVote() { return mapVote; } public void vote(String user,String voteItem){ //1.为该用户增加投票次数 //从记录中取出该用户已有的投票次数 Integer oldVoteCount = mapVoteCount.get(user); if(oldVoteCount == null){ oldVoteCount = 0; } 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); }}

客户端测试:

public class Client {    public static void main(String[] args) {        VoteManager vm = new VoteManager();        for(int i=0;i<9;i++){            vm.vote("u1","A");        }    }}

由此可以看出,状态的转换基本上都是内部行为,主要在状态模式内部来维护;比如对于投票的人员,任何时候他的操作都是投票,但是投票管理对象的处理却不一定一样,会根据投票的次数来判断状态,然后根据状态去选择不同的处理;

场景二: 以支付宝蚂蚁庄园为例进行代码演示

未使用状态模式

public class AntFarm {	static int eatstate = 0;//表示自己吃饭状态	static int vistitorstate = 1;//表示有访客状态	static int state;	public AntFarm() {		state = 0;//初始化时小鸡为吃饭状态	}	public void invite() {		if (state == 0) {			System.out.println("邀请别的小鸡");			state = vistitorstate;//状态修改		} else if (state == 1) {			System.out.println("已有访客,请勿重复邀请");		}	}	public void expel() {		if (state == 1) {			System.out.println("把访客送走");			state = eatstate;		} else if (state == 0) {			System.out.println("当前没有访客");		}	}}

当对象有多种状态的时候再用条件语句显然很不好了,但引入状态模式可以省去条件语句的判断;

使用状态模式

环境类(context):

public class AntFarmContext {	AntFarmState state;//持有一个具体状态的实例,不一定是哪种状态	public AntFarmState getState() {		return state;	}	public void setState(AntFarmState state) {		this.state = state;	}	public void invite(){		state.invite();//委托给具体状态类运行	}	public void expel(){		state.expel();	}}

 抽象状态类(state):

public abstract class AntFarmState {    //写这两个方法就是为了子类完成相应操作中重写	public void  invite(){		System.out.println("已有访客,请勿重复邀请");	}	public void expel(){		System.out.println("当前没有访客");	}}

具体状态类(concreteState):

public class EatingState extends AntFarmState{	AntFarmContext afc;	public EatingState(AntFarmContext afc) {		this.afc=afc;	}	public void invite() {		System.out.println("邀请别的小鸡");        //执行相应操作后在环境类中更改所处的状态,邀请了小鸡此时给环境类设置访客状态		afc.setState(new InvistorState(afc));	}}
public class InvistorState extends AntFarmState{	   AntFarmContext afc;	public InvistorState(AntFarmContext afc) {		this.afc=afc;	}	public void expel() {		System.out.println("把访客送走");		afc.setState(new EatingState(afc));	}}

客户端测试: 

public class Client1 {	public static void main(String[] args) {        AntFarmContext afc=new AntFarmContext();        EatingState es=new EatingState(afc);        afc.setState(es);//环境类设置最初状态        afc.invite();        afc.expel();        afc.expel();        afc.invite();	}}

 

参考文章:

java模式之状态模式:

设计模式之状态模式(state模式):

转载地址:http://fsgtz.baihongyu.com/

你可能感兴趣的文章
NO 157 去掉禅道访问地址中的zentao
查看>>
no available service ‘default‘ found, please make sure registry config corre seata
查看>>
No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
查看>>
no connection could be made because the target machine actively refused it.问题解决
查看>>
No Datastore Session bound to thread, and configuration does not allow creation of non-transactional
查看>>
No fallbackFactory instance of type class com.ruoyi---SpringCloud Alibaba_若依微服务框架改造---工作笔记005
查看>>
No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalanc
查看>>
No mapping found for HTTP request with URI [/...] in DispatcherServlet with name ...的解决方法
查看>>
No mapping found for HTTP request with URI [/logout.do] in DispatcherServlet with name 'springmvc'
查看>>
No module named 'crispy_forms'等使用pycharm开发
查看>>
No module named cv2
查看>>
No module named tensorboard.main在安装tensorboardX的时候遇到的问题
查看>>
No module named ‘MySQLdb‘错误解决No module named ‘MySQLdb‘错误解决
查看>>
No new migrations found. Your system is up-to-date.
查看>>
No qualifying bean of type XXX found for dependency XXX.
查看>>
No qualifying bean of type ‘com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>‘ available
查看>>
No resource identifier found for attribute 'srcCompat' in package的解决办法
查看>>
no session found for current thread
查看>>
No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
查看>>
NO.23 ZenTaoPHP目录结构
查看>>