状态模式
状态模式
状态模式,又称状态机模式,是一种行为型设计模式。它允许对象在其内部状态改变时更改其行为。这种模式是为了减少对象在状态变化时的复杂性。
状态模式可以通过将状态定义为独立的类或对象,将状态转换代码与主对象分离,达到简化代码的目的。当一个对象的状态发生改变时,它通常需要改变它的行为,这就需要在大量代码中进行修改,容易引入 bug。 状态模式通过将状态抽象出来,避免了大量代码的修改,使代码更加简洁和易于维护。
结构
- Context(环境):定义客户端感兴趣的接口,并维护一个当前状态对象的引用。
- State(状态):定义一个接口,用于封装与 Context 的某个状态相关的行为。
- ConcreteState(具体状态):实现状态接口的具体状态对象。同时,它还会处理该状态下的行为。
实现
下面我们以一个投票系统为例,在文章发表一年内,对同一文章进行多次投票,每个投票人只能投一次票。我们采用状态模式实现。
1. 创建 State 接口
public interface VoteState {
void vote(String user, String voteItem, VoteManager voteManager);
}
2. 创建 Context 类
public class VoteManager {
private Map<String, String> mapVote = new HashMap<>();
private Map<String, Integer> mapVoteCount = new HashMap<>();
private VoteState state = new NormalVoteState();
public void vote(String user, String voteItem) {
state.vote(user, voteItem, this);
}
public Map<String, String> getMapVote() {
return mapVote;
}
public void setMapVote(Map<String, String> mapVote) {
this.mapVote = mapVote;
}
public Map<String, Integer> getMapVoteCount() {
return mapVoteCount;
}
public void setMapVoteCount(Map<String, Integer> mapVoteCount) {
this.mapVoteCount = mapVoteCount;
}
public void setState(VoteState state) {
this.state = state;
}
}
3. 创建具体状态类
3.1. NormalVoteState
该状态下可以投票,并记录投票人和投票结果。
public class NormalVoteState implements VoteState {
@Override
public void vote(String user, String voteItem, VoteManager voteManager) {
voteManager.getMapVote().put(user, voteItem);
Integer oldCount = voteManager.getMapVoteCount().get(voteItem);
if (oldCount == null) {
oldCount = 0;
}
voteManager.getMapVoteCount().put(voteItem, oldCount + 1);
System.out.println("投票成功");
voteManager.setState(new RepeatVoteState());
}
}
3.2. RepeatVoteState
该状态下投票人已经投过票,提醒投票人不可重复投票。
public class RepeatVoteState implements VoteState {
@Override
public void vote(String user, String voteItem, VoteManager voteManager) {
String s = voteManager.getMapVote().get(user);
if (s != null) {
System.out.println("请不要重复投票");
return;
}
voteManager.getMapVote().put(user, voteItem);
Integer oldCount = voteManager.getMapVoteCount().get(voteItem);
if (oldCount == null) {
oldCount = 0;
}
voteManager.getMapVoteCount().put(voteItem, oldCount + 1);
System.out.println("投票成功");
voteManager.setState(new SpiteVoteState());
}
}
3.3. SpiteVoteState
在投票期间,如果某个人恶意投票,那么将禁止其参与投票,并且取消其之前的投票权。
public class SpiteVoteState implements VoteState {
@Override
public void vote(String user, String voteItem, VoteManager voteManager) {
if (voteManager.getMapVote().get(user) != null) {
System.out.println("你有恶意刷票行为,取消投票资格");
voteManager.getMapVote().remove(user);
return;
}
voteManager.getMapVote().put(user, voteItem);
Integer oldCount = voteManager.getMapVoteCount().get(voteItem);
if (oldCount == null) {
oldCount = 0;
}
voteManager.getMapVoteCount().put(voteItem, oldCount + 1);
System.out.println("投票成功");
voteManager.setState(new BlackVoteState());
}
}
3.4. BlackVoteState
黑名单状态,即进入黑名单之后,将禁止其参与投票。
public class BlackVoteState implements VoteState {
@Override
public void vote(String user, String voteItem, VoteManager voteManager) {
System.out.println("你已经进入黑名单,禁止登录和使用本系统");
}
}
4. 使用状态模式
public static void main(String[] args) {
VoteManager voteManager = new VoteManager();
for (int i = 0; i < 8; i++) {
voteManager.vote("张三", "投票对象");
}
}
5. 输出结果
投票成功
请不要重复投票
请不要重复投票
请不要重复投票
请不要重复投票
请不要重复投票
你有恶意刷票行为,取消投票资格
你已经进入黑名单,禁止登录和使用本系统
总结
状态模式是一种简单而有效的设计模式,其核心是定义状态类,将状态转换代码与主对象分离,达到更好的松耦合和可扩展性。在生活开发中,当对象有多种状态且状态之间发生转换时,可以考虑使用此模式。