大话设计模式笔记(十三)の状态模式

举个栗子

问题描述

上班的日子,上午状态好,中午想睡觉,下午渐恢复,加班苦煎熬。根据时间的不同体现不同的工作状态。

简单实现

Work

/**
 * 工作类
 * Created by callmeDevil on 2019/8/3.
 */
public class Work {

    private int hour;
    private boolean finish = false;

    public void writeProgram() {
        if (hour < 12) {
            System.out.println(String.format("当前时间:%s点,上午工作,精神百倍", hour));
        } else if (hour < 13) {
            System.out.println(String.format("当前时间:%s点,饿了,午饭;犯困,午休", hour));
        } else if (hour < 17) {
            System.out.println(String.format("当前时间:%s点,下午状态还不错,继续努力", hour));
        } else {
            if (finish) {
                System.out.println(String.format("当前时间:%s点,下班回家了", hour));
            } else {
                if (hour < 21) {
                    System.out.println(String.format("当前时间:%s点,加班哦,疲累至极", hour));
                } else {
                    System.out.println(String.format("当前时间:%s点,不行了,睡着了", hour));
                }
            }
        }
    }

    // 省略 get set 方法

}

测试

public class Test {
    public static void main(String[] args) {
        // 紧急项目
        Work emergencyProjects = new Work();
        emergencyProjects.setHour(9);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(10);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(11);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(12);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(13);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(14);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(17);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(19);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(22);
        emergencyProjects.writeProgram();
        System.out.println("--------------------------");
        emergencyProjects.setFinish(true);
        emergencyProjects.setHour(19);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(22);
        emergencyProjects.writeProgram();
    }
}

测试结果

当前时间:9点,上午工作,精神百倍
当前时间:10点,上午工作,精神百倍
当前时间:11点,上午工作,精神百倍
当前时间:12点,饿了,午饭;犯困,午休
当前时间:13点,下午状态还不错,继续努力
当前时间:14点,下午状态还不错,继续努力
当前时间:17点,加班哦,疲累至极
当前时间:19点,加班哦,疲累至极
当前时间:22点,不行了,睡着了
--------------------------
当前时间:19点,下班回家了
当前时间:22点,下班回家了

存在问题

面向对象设计其实就是希望做到代码的责任分解。 这个类违背了“单一职责原则”。如果公司为了员工的安全而要求员工必须20点之前离开公司(想想就好,现实往往不可能。。),那就会对当前的方法改动,维护出错的风险很大,这点来说违背了“开放-封闭原则”。

状态模式

定义

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

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,那就没必要用状态模式了。

UML图

代码实现

State

/**
 * 抽象状态
 * Created by callmeDevil on 2019/8/3.
 */
public abstract class State {
    public abstract void writeProgram(Work work);
}

ForenoonState

/**
 * 上午工作状态
 * Created by callmeDevil on 2019/8/3.
 */
public class ForenoonState extends State{
    @Override
    public void writeProgram(Work work) {
        if (work.getHour() < 12) {
            System.out.println(String.format("当前时间:%s点,上午工作,精神百倍", work.getHour()));
        } else {
            // 超过12点,转入中午工作状态
            work.setState(new NoonState());
            work.writeProgram();
        }
    }
}

NoonState

/**
 * 中午工作状态
 * Created by callmeDevil on 2019/8/3.
 */
public class NoonState extends State{
    @Override
    public void writeProgram(Work work) {
        if (work.getHour() < 13) {
            System.out.println(String.format("当前时间:%s点,饿了,午饭;犯困,午休", work.getHour()));
        } else {
            // 超过13点,转入下午工作状态
            work.setState(new AfternoonState());
            work.writeProgram();
        }
    }
}

AfternoonState

/**
 * 下午工作状态
 * Created by callmeDevil on 2019/8/3.
 */
public class AfternoonState extends State{
    @Override
    public void writeProgram(Work work) {
        if (work.getHour() < 17) {
            System.out.println(String.format("当前时间:%s点,下午状态还不错,继续努力", work.getHour()));
        } else {
            // 超过17点,转入傍晚工作状态
            work.setState(new EveningState());
            work.writeProgram();
        }
    }
}

EveningState

/**
 * 傍晚工作状态
 * Created by callmeDevil on 2019/8/3.
 */
public class EveningState extends State {
    @Override
    public void writeProgram(Work work) {
        if (work.isTaskFinished()) {
            // 如果完成任务,转入下班状态
            work.setState(new RestState());
        } else {
            if (work.getHour() < 21) {
                System.out.println(String.format("当前时间:%s点,加班哦,疲累至极", work.getHour()));
            } else {
                // 超过21点,转入睡眠工作状态
                work.setState(new SleepingState());
                work.writeProgram();
            }
        }
    }
}

SleepingState

/**
 * 睡眠工作状态
 * Created by callmeDevil on 2019/8/3.
 */
public class SleepingState extends State{
    @Override
    public void writeProgram(Work work) {
        System.out.println(String.format("当前时间:%s点,不行了,睡着了", work.getHour()));
    }
}

RestState

/**
 * 下班工作状态
 * Created by callmeDevil on 2019/8/3.
 */
public class RestState extends State{
    @Override
    public void writeProgram(Work work) {
        System.out.println(String.format("当前时间:%s点,下班回家了", work.getHour()));
    }
}

Work

/**
 * 工作类,此时没有了过长的分支判断语句
 * Created by callmeDevil on 2019/8/3.
 */
public class Work {

    private State current;
    private int hour; // 时间,状态转换的依据
    private boolean taskFinished; // 任务完成,是否能下班的依据

    public Work(){
        // 工作初始化为上午工作状态,即上午9点开始上班
        current = new ForenoonState();
    }

    public void writeProgram(){
        current.writeProgram(this);
    }

    // 省略 get set 方法

}

测试代码与测试结果同上。

总结

  • 好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
  • 将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个 ConcreteState 中,所以通过定义新的子类可以很容易的增加新的状态和转换。
  • 状态模式通过把各种状态转移逻辑分布到 State 的子类之间,来减少相互间的依赖。
  • 当一个对象的行为取决于它的状态,并且必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
(0)

相关推荐

  • 大话设计模式笔记(二)の策略模式

    举个栗子 问题描述 商场收银软件,营业员根据客户所购买的商品单价和数量,向客户收费. 简单实现 /** * 普通实现 * Created by callmeDevil on 2019/6/1. */ ...

  • 大话设计模式笔记(五)の代理模式

    举个栗子 故事是这样的... 一个小伙子喜欢上了隔壁班的一个妹子,但是又不认识,也害羞不好意思主动去说话,于是拜托了同样在这个班的一个朋友去传递自己想要送的礼物... 代码实现 该模式就不上什么简单实 ...

  • 一般过去式和过去完成时的用法及区别习题(一)

    过去完成时在时间上强调"过去的过去",且对过去的某一点造成的某种影响或是结果:而一般过去时只强调过去某一特定的时间,所以判断的关键是看是否有两个过去动作,若只有一个过去动作,则用一 ...

  • 大话设计模式笔记(一)の简单工厂模式

    概要 一个好的程序猿/媛敲出来的代码应该是可维护.可复用.可扩展的,也就是具有较好的灵活性. 为了达到以上目的,在还没敲代码之前,需要事先考虑通过何种方式能够使自己的程序的耦合度降低,最基本的便是面向 ...

  • 【16种英语时态完整版笔记】在英语世界里...

    [16种英语时态完整版笔记] 在英语世界里,你真的理解什么是时态吗?有时,很多老师未必能讲清楚. 中文的时态都是取决于时间状语.比如说:我昨天工作,我今天工作,我明天工作.分别为为过去.现在.将来时态 ...

  • 大话设计模式笔记(七)の原型模式

    举个栗子 问题描述 要求有一个简历类,必须要有姓名,可以设置性别和年龄,可以设置工作经历,最终需要三份简历. 简单实现 简历类 /** * 简历类 * Created by callmeDevil o ...

  • 插画|不复杂的思绪

    英国艺术家/设计师 Maria Ines Gul 对肖像.时尚.书籍封面设计.插图等等都有着浓厚的兴趣. 并不复杂的技法,却有着极强的表现力,和时尚品味.多领域的尝试产生了多种不同的呈现. Your ...

  • 大话设计模式笔记(十七)の迭代器模式

    迭代器模式 定义 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 什么时候用? 当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式. ...

  • 大话设计模式笔记(六)の工厂方法模式

    栗子回顾 简单工厂模式: https://www.cnblogs.com/call-me-devil/p/10926633.html 运算类使用工厂方法模式实现 UML图 代码实现 工厂接口 /** ...

  • 深入学习《大话设计模式》 简单工厂模式

    简单工厂模式 定义:封装改变,既然要封装改变,自然也就要找到需要更改的代码,然后将需要更改的代码用类来封装,这样的思路就是我们简单工厂模式的实现方式了 下面我们通过一则小故事来简述一下我们在项目中为什 ...

  • 设计模式-行为型-状态模式

    状态模式(State): 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到,然后使用if else语句来做状态判断来进行不同情况的处理 ...

  • 大话设计模式笔记(十八)の单例模式

    单例模式 定义 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象.一个最好的办法就是,让类自身负责保存它的唯一实例.这 ...