• 设计模式19---设计模式之状态模式(State)(行为型)


    1.场景模拟

    考虑一个在线投票的应用,分为四种情况
    正常投票
    正常投票以后还继续重复投票
    用户恶意投票
    黑名单用户

    2.不用模式的解决方案

    package demo17.state.example1;
    import java.util.*;
    /**
     * 投票管理
     */
    public class VoteManager {
    	/**
    	 * 记录用户投票的结果,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>();
    	/**
    	 * 投票
    	 * @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){
    			//正常投票
    			//记录到投票记录中
    			mapVote.put(user, voteItem);
    			System.out.println("恭喜你投票成功");
    		}else if(oldVoteCount>1 && oldVoteCount<5){
    			//重复投票
    			//暂时不做处理
    			System.out.println("请不要重复投票");
    		}else if(oldVoteCount >= 5 && oldVoteCount<8){
    			//恶意投票
    			//取消用户的投票资格,并取消投票记录
    			String s = mapVote.get(user);
    			if(s!=null){
    				mapVote.remove(user);
    			}
    			System.out.println("你有恶意刷票行为,取消投票资格");
    		}else if(oldVoteCount>=8){
    			//黑名单
    			//记入黑名单中,禁止登录系统了
    			System.out.println("进入黑名单,将禁止登录和使用本系统");
    		}
    	}
    }
    ************************************************************************************************
    package demo17.state.example1;
    
    
    public class Client {
    	public static void main(String[] args) {
    		VoteManager vm = new VoteManager();
    		for (int i = 0; i < 8; i++) {
    			vm.vote("u1", "A");
    		}
    	}
    }

    3.问题所在(问题分析)

    上述代码看起来很简单,实际上有很大的不妥之处,比如要添加新的功能,那怎么办呢?要在对应的一大堆的控制代码中找出需要的部分,然后进行修改,是很麻烦的。那么怎么很容易的扩展vote()这个方法呢?
    由于刚刚学过了策略模式,很容易就想到要用策略模式来实现,因为感觉这里用策略模式正好。实际上则不然,这里不用策略模式实现,是因为策略模式重心在于分离算法,然后选择实现,大家可以发现,这个案例,没有什么需要计算的算法,都是一些相同的行为的次数的递增罢了,策略模式是不同行为的实现,针对不同的对象使用不同的策略,这里很明显不是,这里是相同的行为的次数的不同,导致结果不同,抽象化以后就是:对象的状态不同,导致结果不同,大家要仔细区分清楚。当然,你看这两个模式的客户端实现就能看出不同来。
    那么,不用策略模式,用什么模式呢?

    4.使用状态模式解决问题

    4.1状态模式定义

    允许一个对象在其内部状态改变时候,改变它的行为,对象看起来似乎修改了他的类。

    4.2状态模式的结构和说明

    结构图跟策略模式基本上是一样的,如下


    4.3状态模式示例代码

    package demo17.state.example2;
    
    
    /**
     * 封装与Context的一个特定状态相关的行为
     */
    public interface State {
    	/**
    	 * 状态对应的处理
    	 * 
    	 * @param sampleParameter
    	 *        示例参数,说明可以传入参数,具体传入 什么样的参数,传入几个参数,由具体应用来具体分析
    	 */
    	public void handle(String sampleParameter);
    }
    **********************************************************************
    package demo17.state.example2;
    
    
    /**
     * 实现一个与Context的一个特定状态相关的行为
     */
    public class ConcreteStateA implements State {
    	public void handle(String sampleParameter) {
    		// 实现具体的处理
    	}
    }
    **********************************************************************
    package demo17.state.example2;
    
    
    /**
     * 实现一个与Context的一个特定状态相关的行为
     */
    public class ConcreteStateB implements State {
    	public void handle(String sampleParameter) {
    		// 实现具体的处理
    	}
    }
    **********************************************************************
    package demo17.state.example2;
    
    
    /**
     * 定义客户感兴趣的接口,通常会维护一个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);
    	}
    }

    5.使用状态模式重写实例代码

    5.1投票接口

    package demo17.state.example3;
    /**
     * 封装一个投票状态相关的行为
     */
    public interface VoteState {
    	/**
    	 * 处理状态对应的行为
    	 * @param user 投票人
    	 * @param voteItem 投票项
    	 * @param voteManager 投票上下文,用来在实现状态对应的功能处理的时候,
    	 *                    可以回调上下文的数据
    	 */
    	public void vote(String user,String voteItem,VoteManager voteManager);
    }

    5.2四个实现

    package demo17.state.example3;
    
    
    public class NormalVoteState implements VoteState{
    	public void vote(String user, String voteItem, VoteManager voteManager) {
    		//正常投票
    		//记录到投票记录中
    		voteManager.getMapVote().put(user, voteItem);
    		System.out.println("恭喜你投票成功");
    	}
    }
    
    
    package demo17.state.example3;
    
    
    public class RepeatVoteState implements VoteState{
    	public void vote(String user, String voteItem, VoteManager voteManager) {
    		//重复投票
    		//暂时不做处理
    		System.out.println("请不要重复投票");
    	}
    }
    
    
    package demo17.state.example3;
    
    
    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("你有恶意刷票行为,取消投票资格");
    	}
    }
    
    
    package demo17.state.example3;
    
    
    public class BlackWarnVoteState implements VoteState{
    	public void vote(String user, String voteItem, VoteManager voteManager) {
    		//待进黑名单警告状态
    		System.out.println("禁止登录和使用系统3天");
    	}
    }

    5.3投票管理

    package demo17.state.example3;
    import java.util.*;
    /**
     * 投票管理
     */
    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);
    	}
    }

    5.4客户端不变

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

    6.状态模式讲解

    6.1状态模式要点

    状态和行为:对象的状态就是指对象实例的属性的值;而行为指的是对象的功能。
    状态模式的功能:分离状态的行为,通过维护状态的变化,来调用不同状态对应不同的功能。
    行为的平行性:注意是平行性,而不是平等性。

    6.2状态模式的调用顺序图

     

    6.3状态模式优缺点

    优点:
    简化应用逻辑控制
    更好的分离状态和行为
    更好的扩展性
    显示化进行状态转换
    缺点:
    一个状态引入一个对应的状态处理类,会使得程序引入太多的状态类,使程序变得杂乱。

    6.4状态模式本质

    根据状态来分离和选择行为

  • 相关阅读:
    Autoit对win系统弹窗的操作
    Linux服务器测试网络连通性
    如何给linux配置两个不同网段的ip
    记下看过并觉得非常有用的文章
    使用python+selenium对12306车票数据读取
    windows系统mysql安装
    Python使用正则匹配re实现eval计算器
    css3[补1]
    Javascript[2]
    Javascript[1]
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3226165.html
Copyright © 2020-2023  润新知