设计模式:状态模式

Posted 我永远信仰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式:状态模式相关的知识,希望对你有一定的参考价值。

【实验内容和要求】
论坛用户等级
回复留言也将增加积分;用户还可以下载文件,下载文件将扣除积分。该系统用户分为三个等级,分别是新手、高手和专家,这三个等级对应三种不同的状态,这三种状态分别定义如下:
(1) 如果积分小于100分,则为新手状态,用户可以发表留言、回复留言,但是不能下载文件。如果积分大于等于1000分,则转换为专家状态;如果积分大于等于100分,则转换为高手状态。
(2) 如果积分大于等于100分但小于1000分,则为高手状态,用户可以发表留言、回复留言,还可以下载文件,而且用户在发表留言时可以获取双倍积分。如果积分小于100分,则转换为新手状态;如果积分大于等于1000分,则转换为专家状态;如果下载文件后积分小于0,则不能下载该文件。
(3) 如果积分大于等于1000分,则为专家状态,用户可以发表留言、回复留言和下载文件,用户除了在发表留言时可以获取双倍积分外,下载文件只扣除所需积分的一半。如果积分小于100分,则转换为新手状态;如果积分小于1000分,但大于等于100,则转换为高手状态;如果下载文件后积分小于0,则不能下载该文件。

【实验目的】

  1. 掌握抽象状态模式(State)的特点
  2. 分析具体问题,使用状态模式进行设计。

【模式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.代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态。

以上是关于设计模式:状态模式的主要内容,如果未能解决你的问题,请参考以下文章

用于从 cloudkit 检索单列的代码模式/片段

是否有在单个活动中处理多个片段的 Android 设计模式?

方向/配置更改后如何维护 ListView 片段状态?

为不同方向使用不同布局时,在方向更改时保存片段状态

Sublime text3最全快捷键清单

csharp C#代码片段 - 使类成为Singleton模式。 (C#4.0+)https://heiswayi.github.io/2016/simple-singleton-pattern-us