其他分享
首页 > 其他分享> > 状态模式

状态模式

作者:互联网

目录

状态模式

案例

张三所在公司欲开发一款纸牌游戏软件,在该游戏软件中用户角色具有入门级(Primary)、熟练级(Secondary)和高手级(Professional)三种等级,角色的等级与其积分相对应,游戏胜利将增加积分,失败则扣除积分。入门级具有最基本的游戏功能 ,熟练级增加了游戏胜利积分加倍功能,高手级在熟练级基础上再增加换牌功能。用程序来表示如下:

1.首先定义了 Player 类:

public class Player {
    // 初始积分为 0
    private int integral = 0;

    // 初始等级为入门级
    private String grade = "入门级";

    public void play() {
        System.out.println("开始游戏");
        System.out.println("当前积分为:" + this.integral + "\t当前等级为:" + this.grade);
        System.out.println("游戏进行中");
        changeCards();
        System.out.println("游戏结束");
        // 这里方便演示结果,直接设置为胜利
        System.out.println("游戏胜利,获得100积分");
        score();
        changeGrade();
        System.out.println("当前积分为:" + this.integral + "\t当前等级为:" + this.grade);
    }

    // 换牌操作
    private void changeCards() {
        if (grade.equals("Primary") || grade.equals("Secondary")) {
            System.out.println("该等级太低,不支持换牌操作");
        } else if (grade.equals("Professional")) {
            System.out.println("换牌成功");
        }
    }

    // 计算得分
    private void score() {
        int integral = 100;
        if (grade.equals("Primary")) {
            System.out.println("正常累加" + integral + "积分");
        } else if (grade.equals("Secondary") || grade.equals("Professional")) {
            integral *= 2;
            System.out.println("获得双倍积分" + integral + "积分");
        }
        this.integral += integral;
    }

    // 转换等级
    private void changeGrade() {
        // 这里假设小于 100 积分为入门级,100-300 为熟练级,大于等于 300 为高手级
        if (this.integral < 100) {
            this.grade = "入门级";
        } else if (this.integral < 300) {
            this.grade = "熟练级";
        } else {
            this.grade = "高手级";
        }
    }
}

2.客户端使用:

public class Main {
    public static void main(String[] args) {
        Player player = new Player();
        player.play();
        System.out.println("--------------------------------------");
        player.play();
        System.out.println("--------------------------------------");
        player.play();
    }
}

3.使用结果:

开始游戏
当前积分为:0	当前等级为:入门级
游戏进行中
该等级太低,不支持换牌操作
游戏结束
游戏胜利,获得100积分
正常累加100积分
当前积分为:100	当前等级为:熟练级
--------------------------------------
开始游戏
当前积分为:100	当前等级为:熟练级
游戏进行中
该等级太低,不支持换牌操作
游戏结束
游戏胜利,获得100积分
获得双倍积分200积分
当前积分为:300	当前等级为:高手级
--------------------------------------
开始游戏
当前积分为:300	当前等级为:高手级
游戏进行中
换牌成功
游戏结束
游戏胜利,获得100积分
获得双倍积分200积分
当前积分为:500	当前等级为:高手级

可以看到玩家通过纸牌游戏,随着积分的不断变化,玩家等级会在三个等级之间相互转化(这里方便演示结果,直接设置为胜利)。但是这里的changeCards()score() 方法都包含状态判断语句,以判断不同状态下该方法如何实现,导致代码非常冗长,可维护性较差。同时也导致了扩展新的状态会修改多个地方。为了解决这些问题,可以使用设计模式中的状态模式对其进行一定的改进,使代码具有更好的灵活性和可扩展性。

模式介绍

(源于Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

角色构成

UML 类图

state-uml

代码改造

下面就通过上面的介绍对纸牌游戏进行改造,

1.首先定义出状态接口:

public abstract class State {
    public abstract String getName();

    protected abstract void changeCards();

    protected abstract int score(int integral);
}

2.三种等级的状态类:

入门级:

public class PrimaryState extends State {
    @Override
    public String getName() {
        return "入门级";
    }

    @Override
    protected void changeCards() {
        System.out.println("该等级太低,不支持换牌操作");
    }

    @Override
    protected int score(int integral) {
        System.out.println("正常累加100积分");
        return integral;
    }
}

熟练级:

public class SecondaryState extends State {
    @Override
    public String getName() {
        return "熟练级";
    }

    @Override
    protected void changeCards() {
        System.out.println("该等级太低,不支持换牌操作");
    }

    @Override
    protected int score(int integral) {
        integral *= 2;
        System.out.println("获得双倍积分" + integral + "积分");
        return integral;
    }
}

高手级:

public class ProfessionalState extends State {
    @Override
    public String getName() {
        return "高手级";
    }

    @Override
    protected void changeCards() {
        System.out.println("换牌成功");
    }

    @Override
    protected int score(int integral) {
        integral *= 2;
        System.out.println("获得双倍积分" + integral + "积分");
        return integral;
    }
}

3.很显然这里的环境(Context)角色就是Player类:

public class Player {
    // 初始积分为 0
    private int integral = 0;

    // 初始等级为入门级
    private State state = new PrimaryState();

    public void play() {
        System.out.println("开始游戏");
        System.out.println("当前积分为:" + this.integral + "\t当前等级为:" + this.state.getName());
        System.out.println("游戏进行中");
        changeCards();
        System.out.println("游戏结束");
        // 这里方便演示结果,直接设置为胜利
        System.out.println("游戏胜利,获得100积分");
        score();
        changeGrade();
        System.out.println("当前积分为:" + this.integral + "\t当前等级为:" + this.state.getName());
    }

    // 换牌操作
    private void changeCards() {
        state.changeCards();
    }

    // 计算得分
    private void score() {
        int integral = 100;
        this.integral += state.score(integral);
    }

    // 转换等级
    private void changeGrade() {
        if (this.integral < 100) {
            this.state = new PrimaryState();
        } else if (this.integral < 300) {
            this.state = new SecondaryState();
        } else {
            this.state = new ProfessionalState();
        }
    }
}

4.客户端使用

public class Main {
    public static void main(String[] args) {
        Player player = new Player();
        player.play();
        System.out.println("--------------------------------------");
        player.play();
        System.out.println("--------------------------------------");
        player.play();
    }
}

5.使用结果:

开始游戏
当前积分为:0	当前等级为:入门级
游戏进行中
该等级太低,不支持换牌操作
游戏结束
游戏胜利,获得100积分
正常累加100积分
当前积分为:100	当前等级为:熟练级
--------------------------------------
开始游戏
当前积分为:100	当前等级为:熟练级
游戏进行中
该等级太低,不支持换牌操作
游戏结束
游戏胜利,获得100积分
获得双倍积分200积分
当前积分为:300	当前等级为:高手级
--------------------------------------
开始游戏
当前积分为:300	当前等级为:高手级
游戏进行中
换牌成功
游戏结束
游戏胜利,获得100积分
获得双倍积分200积分
当前积分为:500	当前等级为:高手级

可以看到,现在玩家类通过状态模式的改造,代码简洁了许多,主要是去掉了changeCards()score()方法中的状态判断,而结果也是和改造前一样的。同时代码扩展性也是很强的,比如要增加一个状态,只需要增加一个状态类,并修改changeGrade()方法就可以了。

总结

1.主要优点

2.主要缺点

3.适用场景

参考资料

本篇文章github代码地址:https://github.com/Phoegel/design-pattern/tree/main/state
转载请说明出处,本篇博客地址:https://www.cnblogs.com/phoegel/p/14208328.html

标签:状态,积分,integral,System,模式,println,out
来源: https://www.cnblogs.com/phoegel/p/14208328.html