大话设计模式读书笔记(状态模式)

人物:大鸟,小菜

事件:小菜向大鸟抱怨经常加班,并向大鸟阐述了一天上班各时间段自己的工作状态,然后大鸟借这个事给小菜讲解了状态模式


状态模式:

1.小菜用代码描述自己一天不同时间段的状态

2.改进代码,面向对象

3.了解什么是状态模式

4.进一步改进代码,使用状态模式

5.了解状态模式和策略模式的区别

用代码描述一天状态

@Slf4j
public class WriteProgram {
    static int hour = 0;
    static boolean workFinished = false;

    public static void writeProgram() {
        if (hour < 12) {
            log.info("当前时间:{}点,上午工作,精神百倍", hour);
        } else if (hour < 13) {
            log.info("当前时间:{}点,饿了,午饭:犯困,午休", hour);
        } else if (hour < 17) {
            log.info("当前时间:{}点,下午状态还不错,继续努力", hour);
        } else {
            if (workFinished) {
                log.info("当前时间:{}点 下班回家了", hour);
            } else {
                log.info("当前时间:{}点 不行了,睡着了。", hour);
            }
        }
    }

    public static void main(String[] args) {
        hour = 9;
        writeProgram();
        hour = 10;
        writeProgram();
        hour = 12;
        writeProgram();
        hour = 13;
        writeProgram();
        hour = 14;
        writeProgram();
        hour = 17;

        workFinished = true;
        writeProgram();
        hour = 19;
        writeProgram();
        hour = 22;
        writeProgram();
    }
}

大鸟:你这不还是面向过程开发么,你面向对象至少应该有个工作类吧

工作状态分类版

抽离出的工作类:

@Slf4j
@Data
public class Work {
    private int hour;
    private boolean finish = false;
    public boolean taskFinished;

    public void writeProgram() {
        if (hour < 12) {
            log.info("当前时间:{}点,上午工作,精神百倍", hour);
        } else if (hour < 13) {
            log.info("当前时间:{}点,饿了,午饭:犯困,午休", hour);
        } else if (hour < 17) {
            log.info("当前时间:{}点,下午状态还不错,继续努力", hour);
        } else {
            if (finish) {
                log.info("当前时间:{}点 下班回家了", hour);
            } else {
                log.info("当前时间:{}点 不行了,睡着了。", hour);
            }
        }
    }
}

客户端代码:

@Slf4j
public class WriteProgram {
    public static void main(String[] args) {
        Work emergencyProjects = new Work();
        emergencyProjects.setHour(9);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(10);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(12);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(13);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(14);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(17);

        emergencyProjects.setTaskFinished(false);
        emergencyProjects.writeProgram();

        emergencyProjects.setHour(19);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(22);
        emergencyProjects.writeProgram();
    }
}

结果输出:

当前时间:9点,上午工作,精神百倍
当前时间:10点,上午工作,精神百倍
当前时间:12点,饿了,午饭:犯困,午休
当前时间:13点,下午状态还不错,继续努力
当前时间:14点,下午状态还不错,继续努力
当前时间:17点 不行了,睡着了。
当前时间:19点 不行了,睡着了。
当前时间:22点 不行了,睡着了。

大鸟:这种设计有一个问题就是,方法过长导致了坏味道,面向对象设计其实就是为了责任分解,work类违背了单一职责原则,而且万一有新加判断,要在if...else...加逻辑,破坏了开放封闭原则,用状态模式可以更好的设计这个事件

状态模式

1.概念:当一个对象的内在状态改变时,允许改变其行为,这个对象像是改变了其类

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

3.代码结构图:

首先实现State类,是抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为

public abstract class State {
    public abstract void handle(Context context);
}

ConcreteStateA,ConcreteStateB都是具体的状态,每一个子类实现一个与Context的一个状态相关的行为

public class ConcreteStateA extends State {

    @Override
    public void handle(Context context) {
        context.setState(new ConcreteStateB());
    }
}
public class ConcreteStateB extends State{

    @Override
    public void handle(Context context) {
        context.setState(new ConcreteStateA());
    }
}

Context类,维护每一个ContextState子类的实例,这个实例定义当前的状态

@Data
public class Context {
    private State state;

    public Context(State state) {
        this.state = state;
    }

    public void request() {
        state.handle(this);
    }
}

客户端代码:

@Slf4j
public class WriteProgram {
    public static void main(String[] args) {
       Context c = new Context(new ConcreteStateA());
       c.request();
       c.request();
       c.request();
       c.request();
    }
}

状态模式的好处与用处:

1.好处:将与特定状态相关的行为局部化,并且将不同状态的行为分割开来(消除了庞大的条件分支语句)

2.什么时候用:当一个对象的行为取决于它的状态,并且它必须在运行时要根据状态改变它的行为时,就可以用状态模式了

工作状态--状态模式版

 抽象状态类:

public abstract class State {
    public abstract void writeProgram(Work w);
}

各个时间段的状态类:

上午状态工作类:

@Slf4j
public class ForenoonState extends State {

    @Override
    public void writeProgram(Work w) {
        if (w.getHour() < 12) {
            log.info("当前时间:{}点,上午工作,精神百倍", w.getHour());
        } else {
            w.setState(new AfternoonState());
            w.writeProgram();
        }
    }
}

中午工作状态类:

@Slf4j
public class NoonState extends State {
@Override
public void writeProgram(Work w) {
if (w.getHour() < 13) {
log.info("当前时间:{}点 饿了,午饭:犯困,午休。", w.getHour());
} else {
w.setState(new AfternoonState());
w.writeProgram();
}
}
}

下午状态工作类:

@Slf4j
public class AfternoonState extends State {
    @Override
    public void writeProgram(Work w) {
        if (w.getHour() < 17) {
            log.info("当前时间:{}点,下午状态不错,继续努力", w.getHour());
        } else {
            w.setState(new EveningState());
            w.writeProgram();
        }
    }
}

傍晚状态工作类:

@Slf4j
public class EveningState extends State {
    @Override
    public void writeProgram(Work w) {
        if (w.taskFinished) {
            w.setState(new RestState());
            w.writeProgram();
        } else {
            if (w.getHour() < 21) {
                log.info("当前时间:{}点 加班哦,疲累之极", w.getHour());
            } else {
                w.setState(new SleepingState());
                w.writeProgram();
            }
        }
    }
}

睡眠状态工作类:

@Slf4j
public class SleepingState extends State {
    @Override
    public void writeProgram(Work w) {
        log.info("当前时间:{}点不行了,睡着了", w.getHour());
    }
}

下班休息状态类:

@Slf4j
public class RestState extends State {
    @Override
    public void writeProgram(Work w) {
        log.info("当前时间:{}点下班回家了", w.getHour());
    }
}

工作类:

public class Work {
    private int hour;
    private boolean finish = false;
    public boolean taskFinished;
    private State state;

    public Work() {
        state = new ForenoonState();
    }

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

这样客户端代码没有改动,程序却更加灵活了

状态模式和策略模式的区别

策略模式:其思想是针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换。而且策略模式的客户端必须对所有的策略类相当了解,明确当前场景下各种策略的利弊,权衡在当前场景下应该使用哪种策略,也就是说策略类对客户端是暴露的。

状态模式:允许一个对象在其内部状态改变时改变它的行为。它依赖于其状态的变化时其内部的行为发生变化,将动作委托到代表当前状态的对象,对外表现为类发生了变化。

原文地址:https://www.cnblogs.com/wencheng9012/p/13434935.html