设计模式:状态模式
Posted 我永远信仰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式:状态模式相关的知识,希望对你有一定的参考价值。
【实验内容和要求】
论坛用户等级
回复留言也将增加积分;用户还可以下载文件,下载文件将扣除积分。该系统用户分为三个等级,分别是新手、高手和专家,这三个等级对应三种不同的状态,这三种状态分别定义如下:
(1) 如果积分小于100分,则为新手状态,用户可以发表留言、回复留言,但是不能下载文件。如果积分大于等于1000分,则转换为专家状态;如果积分大于等于100分,则转换为高手状态。
(2) 如果积分大于等于100分但小于1000分,则为高手状态,用户可以发表留言、回复留言,还可以下载文件,而且用户在发表留言时可以获取双倍积分。如果积分小于100分,则转换为新手状态;如果积分大于等于1000分,则转换为专家状态;如果下载文件后积分小于0,则不能下载该文件。
(3) 如果积分大于等于1000分,则为专家状态,用户可以发表留言、回复留言和下载文件,用户除了在发表留言时可以获取双倍积分外,下载文件只扣除所需积分的一半。如果积分小于100分,则转换为新手状态;如果积分小于1000分,但大于等于100,则转换为高手状态;如果下载文件后积分小于0,则不能下载该文件。
【实验目的】
- 掌握抽象状态模式(State)的特点
- 分析具体问题,使用状态模式进行设计。
【模式UML图】
【模式代码】
/**
* 抽象状态类,封装环境对象中特定状态所应对应的行为。
*/
public abstract class AbstractState {
protected ForumAccount acc;//保留状态持有者的引用,以便对其进行操作
public void setAcc(ForumAccount acc) {
this.acc = acc;
}
//抽象方法
public abstract void checkState();
public abstract void downloadFile(int score);
public abstract void writeNote(int score);
public abstract void replyNote(int score);
}
/**
* 环境类,也称为上下文,维护一个当前状态
*/
public class ForumAccount {
/*所有状态*/
private AbstractState highState;
private AbstractState middleState;
private AbstractState primaryState;
private AbstractState state;//当前状态
private int point; //账户当前积分
private int score; //消耗或奖励的积分
private String name;
public ForumAccount(String name, int point) throws Exception {
//初始化账号数据
this.name = name;
this.point = point;
//初始化所有状态
highState = new HighState(this);
middleState = new MiddleState(this);
primaryState = new PrimaryState(this);
if (point<0){
throw new Exception("初始化积分不能小于0");
}
if (point < 100) {
state = primaryState;
} else if (point < 1000) {
state = middleState;
}else {
state = highState;
}
}
public void downloadFile(int score) {
this.state.downloadFile(score);
this.state.checkState();
}
public void writeNote(int score) {
this.state.writeNote(score);
this.state.checkState();
}
public void replyNote(int score) {
this.state.replyNote(score);
this.state.checkState();
}
public AbstractState getState() {
return state;
}
public void setState(AbstractState state) {
/**
* 比如现在是专家,要改变成高手。
* 1将当前状态(专家)改变为高手
* 2将账号权限状态也设置为上下文(高手)
*/
this.state = state;
this.state.setAcc(this);
}
//此处省略了大量的get和set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//新手状态
public class PrimaryState extends AbstractState {
public PrimaryState(ForumAccount acc) {
this.acc=acc;
}
@Override
public void checkState() {
if (acc.getPoint() > 1000) {
acc.setState(acc.getHighState());
System.out.println("等级发生变化,当前等级为:" + acc.getState().getClass().getSimpleName());
} else if (acc.getPoint() > 100) {
acc.setState(acc.getMiddleState());
System.out.println("等级发生变化,当前等级为:" + acc.getState().getClass().getSimpleName());
}
}
@Override
public void downloadFile(int score) {
if (acc.getPoint() - score < 0) {
System.out.println("下载失败,积分不足!");
} else {
int num = acc.getPoint() - score;
acc.setPoint(num);
System.out.println("新手下载文件。本次下载消耗积分为:" + score + " 剩余积分为:" + acc.getPoint());
}
}
@Override
public void writeNote(int score) {
int num = acc.getPoint() + score;
acc.setPoint(num);
System.out.println("新手发表留言。本次获得积分为:" + score + " 剩余积分为:" + acc.getPoint());
}
@Override
public void replyNote(int score) {
int num = acc.getPoint() + score;
acc.setPoint(num);
System.out.println("新手回复留言。本次获得积分为:" + score + " 剩余积分为:" + acc.getPoint());
}
}
//高手状态
public class MiddleState extends AbstractState {
public MiddleState(ForumAccount acc) {
this.acc = acc;
}
@Override
public void checkState() {
if (acc.getPoint() < 100) {
acc.setState(acc.getPrimaryState());
System.out.println("等级发生变化,当前等级为:" + acc.getState().getClass().getSimpleName());
} else if (acc.getPoint() >= 1000) {
acc.setState(acc.getHighState());
System.out.println("等级发生变化,当前等级为:" + acc.getState().getClass().getSimpleName());
}
}
@Override
public void downloadFile(int score) {
if (acc.getPoint() - score < 0) {
System.out.println("下载失败,积分不足!");
} else {
int num = acc.getPoint() - score;
acc.setPoint(num);
System.out.println("高手下载文件。本次下载消耗积分为:" + score + " 剩余积分为:" + acc.getPoint());
}
}
@Override
public void writeNote(int score) {
int num = acc.getPoint() + score * 2;
acc.setPoint(num);
System.out.println("高手发表留言。本次获得积分为:" + score * 2 + " 剩余积分为:" + acc.getPoint());
}
@Override
public void replyNote(int score) {
int num = acc.getPoint() + score;
acc.setPoint(num);
System.out.println("高手回复留言。本次获得积分为:" + score + " 剩余积分为:" + acc.getPoint());
}
}
//专家状态
public class HighState extends AbstractState {
public HighState(ForumAccount acc) {
this.acc = acc;
}
@Override
public void checkState() {
if (acc.getPoint() < 100) {
acc.setState(acc.getPrimaryState());
System.out.println("等级发生变化,当前等级为:" + acc.getState().getClass().getSimpleName());
} else if (acc.getPoint() < 1000) {
acc.setState(acc.getMiddleState());
System.out.println("等级发生变化,当前等级为:" + acc.getState().getClass().getSimpleName());
}
}
@Override
public void downloadFile(int score) {
if (acc.getPoint() - score / 2 < 0) {
System.out.println("下载失败,积分不足!");
} else {
int num = acc.getPoint() - score / 2;
acc.setPoint(num);
System.out.println("专家下载文件。本次下载消耗积分为:" + score / 2 + " 剩余积分为:" + acc.getPoint());
}
}
@Override
public void writeNote(int score) {
int num = acc.getPoint() + score * 2;
acc.setPoint(num);
System.out.println("专家发表留言。本次获得积分为:" + score * 2 + " 剩余积分为:" + acc.getPoint());
}
@Override
public void replyNote(int score) {
int num = acc.getPoint() + score;
acc.setPoint(num);
System.out.println("专家回复留言。本次获得积分为:" + score + " 剩余积分为:" + acc.getPoint());
}
}
public class Client {
public static void main(String[] args) throws Exception {
ForumAccount account = new ForumAccount("爹爹", 1200);
System.out.println("当前帐号:" + account.getName() +
",等级为:" + account.getState().getClass().getSimpleName());
account.downloadFile(2000);
account.downloadFile(1500);
account.writeNote(5);
account.replyNote(80);
account.writeNote(5);
account.downloadFile(280);
account.downloadFile(10);
System.out.println("==================================");
ForumAccount account1 = new ForumAccount("爸爸", 40);
System.out.println("当前帐号:" + account1.getName() +
",等级为:" + account1.getState().getClass().getSimpleName());
account1.downloadFile(10);
account1.downloadFile(106);
account1.replyNote(90);
account1.writeNote(6);
}
}
【运行截图】
【实验小结】
状态模式主要适用于以下情况:
1.对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为。
2.代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态。
以上是关于设计模式:状态模式的主要内容,如果未能解决你的问题,请参考以下文章
是否有在单个活动中处理多个片段的 Android 设计模式?
csharp C#代码片段 - 使类成为Singleton模式。 (C#4.0+)https://heiswayi.github.io/2016/simple-singleton-pattern-us