← 返回首页
设计模式基础教程(三十)
发表时间:2021-08-30 17:31:07
状态模式

1.状态模式 在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的 (stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。

在UML中可以使用状态图来描述对象状态的变化。

状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

状态模式包含如下角色: - Context: 环境类 - State: 抽象状态类 - ConcreteState: 具体状态类

2.实例

在某论坛系统中,用户可以发表留言,发表留言将增加积分;用户也可以回复留言,回复留言也将增加积分;用户还可以下载文件,下载文件将扣除积分。该系统用户分为三个等级,分别是新手、高手和专家,这三个等级对应三种不同的状态,这三种状态分别定义如下:

  1. 如果积分小于100分,则为新手状态,用户可以发表留言、回复留言,但是不能下载文件。如果积分大于等于1000分,则转换为专家状态;如果积分大于等于100分,则转换为高手状态。
  2. 如果积分大于等于100分但小于1000分,则为高手状态,用户可以发表留言、回复留言,还可以下载文件,而且用户在发表留言时可以获取双倍积分。如果积分小于100分,则转换为新手状态;如果积分大于等于1000分,则转换为专家状态;如果下载文件后积分小于0,则不能下载该文件。
  3. 如果积分大于等于1000分,则为专家状态,用户可以发表留言、回复留言和下载文件,用户除了在发表留言时可以获取双倍积分外,下载文件只扣除所需积分的一半。如果积分小于100分,则转换为新手状态;如果积分小于1000分,但大于等于100,则转换为高手状态;如果下载文件后积分小于0,则不能下载该文件。

项目结构图如下:

定义论坛积分类

public class ForumAccount {

    private AbstractState state;
    private String name;
    public ForumAccount(String name) {
        this.name = name;
        this.state=new PrimaryState(this);
        System.out.println(this.name+"注册成功!");
        System.out.println("================");

    }
    public AbstractState getState() {
        return state;
    }
    public void setState(AbstractState state) {
        this.state = state;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public void downLoadFile(int score){
        state.downLoadFile(score);
    }

    public void writeNote(int score){
        state.writeNote(score);
    }

    public void replyNote(int score){
        state.replyNote(score);
    }
}

定义论坛状态抽象类

public abstract class AbstractState {

    protected ForumAccount forumAccount;
    protected int point;
    protected String stateName;

    public abstract void checkState(int score);

    public void downLoadFile(int score) {
        System.out.println(forumAccount.getName()+"下载文件,扣除"+score+"积分!");
        this.point-=score;
        this.checkState(score);
        System.out.println("剩余积分为:"+this.point+",当前级别 为:"+forumAccount.getState().stateName+".");
    }

    public void writeNote(int score) {
        System.out.println(forumAccount.getName()+"发布留言,增加"+score+"积分。");
        this.point+=score;
        this.checkState(score);
        System.out.println("剩余积分为:"+this.point+",当前级别为:"+forumAccount.getState().stateName+".");
    }

    public void replyNote(int score) {
        System.out.println(forumAccount.getName()+"回复留言,增加"+score+"积分。");
        this.point+=score;
        this.checkState(score);
        System.out.println("剩余积分为:"+this.point+",当前级别为:"+forumAccount.getState().stateName+".");
    }

    public int getPoint() {
        return point;
    }

    public void setPoint(int point) {
        this.point = point;
    }

    public String getStateName() {
        return stateName;
    }

    public void setStateName(String stateName) {
        this.stateName = stateName;
    }
}

初级会员类

public class PrimaryState extends AbstractState {

    public PrimaryState(AbstractState state) {
        this.forumAccount=state.forumAccount;
        this.point=state.getPoint();
        this.stateName="新手";
    }

    public PrimaryState(ForumAccount forumAccount) {
        this.point=0;
        this.forumAccount=forumAccount;
        this.stateName="新手";
    }

    public void downLoadFile(int score){
        System.out.println("对不起,"+forumAccount.getName()+"您没有下载文件的权限!");
    }
    @Override
    public void checkState(int score) {
        if(this.point>=1000){
            forumAccount.setState(new HightState(this));
        }else if(this.point>=100){
            forumAccount.setState(new MiddleState(this));
        }

    }
}

中级会员类

public class MiddleState extends AbstractState {

    public MiddleState(AbstractState state) {
        this.forumAccount=state.forumAccount;
        this.point=state.getPoint();
        this.stateName="高手";
    }

    public void writeNote(int score){
        System.out.println(forumAccount.getName()+"发布留言,增加"+score+"*2个积分");
        this.point+=score*2;
        this.checkState(score);
        System.out.println("剩余积分为:"+this.point+",当前级别为:"+forumAccount.getState().stateName+".");
    }

    @Override
    public void checkState(int score) {
        if(point>=1000){
            forumAccount.setState(new HightState(this));
        }else if(this.point<0){
            System.out.println("余额不足,文件下载失败!");
            this.point+=score;
        }else if(this.point<100){
            forumAccount.setState(new PrimaryState(this));
        }
    }
}

超级会员类

public class HightState extends AbstractState {

    public HightState(AbstractState state) {
        this.forumAccount=state.forumAccount;
        this.point=state.getPoint();
        this.stateName="专家";
    }

    public void writeNote(int score){
        System.out.println(forumAccount.getName()+"发布留言,增加积分"+score+"*2个积分.");
        this.point+=score*2;
        this.checkState(score);
        System.out.println("剩余积分为:"+this.point+",当前级别为:"+forumAccount.getState().stateName+".");
    }

    public void downLoadFile(int score){
        System.out.println(forumAccount.getName()+"下载文件,扣除积分"+score+"/2积分。");
        this.point-=score/2;
        this.checkState(score);
        System.out.println("剩余积分为:"+this.point+",当前级别为:"+forumAccount.getState().stateName+".");
    }

    @Override
    public void checkState(int score) {
        if(this.point<0){
            System.out.println("余额不足,文件下载失败!");
            this.point+=score;
        }else if(this.point<=100){
            forumAccount.setState(new PrimaryState(this));
        }else if(this.point<=1000){
            forumAccount.setState(new MiddleState(this));
        }
    }
}

测试类

public class TestStateDemo01 {

    public static void main(String[] args) {
        ForumAccount forumAccount=new ForumAccount("张三");
        forumAccount.writeNote(20);
        System.out.println("===============");
        forumAccount.downLoadFile(20);
        System.out.println("============");
        forumAccount.replyNote(100);
        System.out.println("=======");
        forumAccount.writeNote(40);
        System.out.println("=======");
        forumAccount.downLoadFile(80);
        System.out.println("=====");
        forumAccount.downLoadFile(150);
        System.out.println("=======");
        forumAccount.writeNote(1000);
        System.out.println("=======");
        forumAccount.downLoadFile(80);
        System.out.println("======");
    }
}

运行结果:
张三注册成功!
================
张三发布留言,增加20积分。
剩余积分为:20,当前级别为:新手.
===============
对不起,张三您没有下载文件的权限!
============
张三回复留言,增加100积分。
剩余积分为:120,当前级别为:高手.
=======
张三发布留言,增加40*2个积分
剩余积分为:200,当前级别为:高手.
=======
张三下载文件,扣除80积分!
剩余积分为:120,当前级别 为:高手.
=====
张三下载文件,扣除150积分!
余额不足,文件下载失败!
剩余积分为:120,当前级别 为:高手.
=======
张三发布留言,增加1000*2个积分
剩余积分为:2120,当前级别为:专家.
=======
张三下载文件,扣除积分80/2积分。
剩余积分为:2080,当前级别为:专家.
======