1、定义:
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了他的类。
2、代码:
/**
* 封装一个投票状态的行为
*/
public interface VoteState {
/**
* 处理状态对应的行为
* @param user 投票人
* @param voteItem 投票项
* @param voteManager 投票上下文,用来实现状态对应的功能处理的时候,可以回调上下文的数据
*/
public void vote(String user,String voteItem,VoteManager voteManager);
}
/**
* 正常投票
*/
public class NormalVoteState implements VoteState {
public void vote(String user, String voteItem, VoteManager voteManager) {
//正常投票
//记录到投票记录中
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("记入黑名单中,将禁止登陆和使用本系统");
}
}
//投票管理类
public class VoteManager {
/**
* 持有状态处理对象
*/
private VoteState state=null;
/**
* 记录用户投票的结果,Map<用户名,投票的选项>
*/
private Map<String,String> mapVote=new HashMap<String, String>();
/**
* 记录用户投票次数Map<用户名,投票次数>
*/
private Map<String,Integer> mapVoteCount=new HashMap<String, Integer>();
/**
* 获取记录用户投票结果
* @return
*/
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++;
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{//黑名单投票
state=new BlackVoteState();
}
state.vote(user,voteItem,this);
}
}
Client类:
public class Client {
public static void main(String[] args) {
VoteManager vm=new VoteManager();
for (int i=0;i<10;i++){
vm.vote("user1","A");
}
}
}
结果输出:
正常投票。
请不要重复投票!
请不要重复投票!
请不要重复投票!
记入黑名单中,将禁止登陆和使用本系统
你有恶意刷票行为,取消投票资格
你有恶意刷票行为,取消投票资格
记入黑名单中,将禁止登陆和使用本系统
记入黑名单中,将禁止登陆和使用本系统
记入黑名单中,将禁止登陆和使用本系统
3、讲解
3.1、状态和行为
状态:指的是对象实例的属性的值
行为:指的就是对象的功能,具体点说,行为大多可以对应到方法上。
状态模式的功能就是分离状态的行为,通过维护状态的变化,来调用不同状态对象的不同功能。
也就是说,状态和行为是相关联的,他们的关系可以描述为:状态决定行为。
3.2、行为的平行性
平行性指的是各个状态的行为所处的层次是一样的,相互是独立的,没有关联的,是根据不同的状态来决定到底走平行线的哪一条。行为不同,对应的实现也是不同的,相互之间是不可替换的。
平等性 强调的是可替换性,同一行为发生时,可以根据条件挑选任意一个实现来进行处理。
3.3、状态模式和策略模式区别
结构万全相同,但是目的、实现、本质却是完全不一样的。行为也是一个重要的区别,状态模式是平行性的,不可相互替换的。
策略模式的行为是平等性的,是可以相互替换的。
3.4、 状态的维护和转换控制
状态的维护:是指维护状态的数据,给状态设置不同的状态值。
状态的转换:是根据状态的变化来选择不同的状态处理对象。
通常在两个地方可以进行状态的维护和转换控制
- 在上下文中。状态本身通常被实现为上下文对象的状态,因此可以在上下文中进行状态维护,当然也就可以控制状态的转换了。上面投票实例就是采用这种方式。
- 在状态的处理类中。当每个状态处理对象处理完自身状态所对应的功能后,可以根据需要指定后继状态,以便让应用能正确处理后续请求。如下实例:
/**
* 封装一个投票状态的行为
*/
public interface VoteState {
/**
* 处理状态对应的行为
* @param user 投票人
* @param voteItem 投票项
* @param voteManager 投票上下文,用来实现状态对应的功能处理的时候,可以回调上下文的数据
*/
public void vote(String user, String voteItem, VoteManager voteManager);
}
/**
* 正常投票
*/
public class NormalVoteState implements VoteState {
public void vote(String user, String voteItem, VoteManager voteManager) {
//正常投票
//记录到投票记录中
voteManager.getMapVote().put(user,voteItem);
System.out.println("恭喜您投票成功。");
//正常投票完成,维护下一个状态,同一个人再投票就重复了。
voteManager.getMapState().put(user,new RepeatVoteState());
}
}
/**
* 重复投票
*/
public class RepeatVoteState implements VoteState {
public void vote(String user, String voteItem, VoteManager voteManager) {
//重复投票
//暂不处理
System.out.println("请不要重复投票!");
//重复投票完成,维护下一个状态,重复投票5次,就算恶意投票了
if(voteManager.getVoteStateCount().get(user)>=4){
voteManager.getMapState().put(user,new SpiteVoteState());
}
}
}
/**
* 恶意投票
*/
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("你有恶意刷票行为,取消投票资格");
//恶意投票完成,投票到8次,就进入黑名单
if(voteManager.getVoteStateCount().get(user)>=7){
voteManager.getMapState().put(user,new BlackVoteState());
}
}
}
/**
* 黑名单投票
*/
public class BlackVoteState implements VoteState {
public void vote(String user, String voteItem, VoteManager voteManager) {
//黑名单
//记入黑名单中,禁止登陆系统了
System.out.println("记入黑名单中,将禁止登陆和使用本系统");
}
}
public class VoteManager {
/**
* 持有状态处理对象
*/
private VoteState state=null;
/**
* 记录当前每个用户对应的状态处理对象,每个用户当前的状态是不同的
*/
private Map<String,VoteState> mapState=new HashMap<String, VoteState>();
/**
* 记录用户投票的结果,Map<用户名,投票的选项>
*/
private Map<String,String> mapVote=new HashMap<String, String>();
/**
* 记录用户投票次数Map<用户名,投票次数>
*/
private Map<String,Integer> mapVoteCount=new HashMap<String, Integer>();
/**
* 获取记录用户投票结果
* @return
*/
public Map<String,String> getMapVote(){
return mapVote;
}
//获取记录每个用户对应的状态处理对象状态
public Map<String,VoteState> getMapState(){
return mapState;
}
public Map<String,Integer> getVoteStateCount(){
return mapVoteCount;
}
/**
* 投票
* @param user
* @param voteItem
*/
public void vote(String user,String voteItem){
//1、先为该用户增加投票的次数
Integer oldVoteCount=mapVoteCount.get(user);
if(oldVoteCount==null){
oldVoteCount=0;
}
oldVoteCount++;
mapVoteCount.put(user,oldVoteCount);
//2、获得该用户的投票状态
VoteState state=mapState.get(user);
if(state==null){
state=new NormalVoteState();
}
state.vote(user,voteItem,this);
}
}
public class Client {
public static void main(String[] args) {
VoteManager vm=new VoteManager();
for (int i=0;i<10;i++){
vm.vote("user1","A");
}
}
}
恭喜您投票成功。
请不要重复投票!
请不要重复投票!
请不要重复投票!
你有恶意刷票行为,取消投票资格
你有恶意刷票行为,取消投票资格
你有恶意刷票行为,取消投票资格
记入黑名单中,将禁止登陆和使用本系统
记入黑名单中,将禁止登陆和使用本系统
记入黑名单中,将禁止登陆和使用本系统
选用何种方式?
- 如果状态转换的规则是一定的,一般不需要进行什么扩展规则,适合上下中统一进行状态维护。
- 如果状态的转换取决于前一个状态动态处理的结果,或者依赖于外部数据,为了增强灵活性,这种情况下,在状态处理类中进行状态的维护。