博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式-状态模式(25)
阅读量:7022 次
发布时间:2019-06-28

本文共 4035 字,大约阅读时间需要 13 分钟。

定义

状态模式(State Pattern)又称为状态对象模式,该模式允许一个对象在其内部状态改变的时候改变行为。

英文:Allow an object to alert its behavior when its internal state changes.The object will appear to change its class.

翻译:允许一个对象内在状态发生改变时改变行为,使得这个对象看起来像改变了类型。

状态模式的核心是封装,状态的变更引起行为的变动,从外部看来就好像该对象对应的类发生改变一样。

角色

抽象状态(State)角色:该角色用以封装环境的一个特定的状态所对应的行为。

具体状态(Concrete State)角色:该角色实现环境的某一个状态所对应的行为。

环境(Context)角色:该角色定义客户端需要的接口,并负责具体状态的切换。它会保留一个具体状态类的实例,该实例给出环境对象的现有状态。

/** * 抽象状态 */public abstract class State {    //定义一个环境角色    protected Context context;    //设置环境    public void setContext(Context context){        this.context = context;    }    //抽象行为    public abstract void handle();}/** * 具体状态 */public class ConcreteState1 extends State {    //状态1的行为逻辑处理    @Override    public void handle() {        System.out.println("行为一的逻辑处理");    }}/** * 具体状态2 */public class ConcreteState2 extends State {    //状态2的行为逻辑处理    @Override    public void handle() {        System.out.println("行为二的逻辑处理");    }}/** * 环境角色 */public class Context {    //定义状态    public static State STATE1 = new ConcreteState1();    public static State STATE2 = new ConcreteState2();    //当前状态    private State currentState;    //获取当前状态    public State getCurrentState() {        return currentState;    }    //设置当前状态    public void setCurrentState(State currentState) {        this.currentState=currentState;        //设置状态的环境        currentState.setContext(this);    }    //行为委托    public void handle1(){        //切换到状态1        this.setCurrentState(STATE1);        this.currentState.handle();    }    //行为委托    public void handle2(){        //切换到状态2        this.setCurrentState(STATE2);        this.currentState.handle();    }}public class Main {    public static void main(String[] args) {        //定义环境角色        Context context = new Context();        //执行行为        context.handle1();        context.handle2();    }}

从运行结果看,状态模式隐藏了状态的变化过程,状态的变化引起行为的变化。在外只能看到行为的变化,而不用知道是状态变化引起的。

优点

  • 结构清晰。
  • 遵循设计原则。
  • 封装性非常好。 

缺点 

  • 子类太多,不易管理。

效果

  1. 状态模式需要对每一个系统可能取得的状态建立一个状态类的子类。当系统的状态发生变化时,系统便改变所选的子类。所有与一个特定的状态有关的行为都被包装到一个特定的对象里面,这使得行为的定义局域化。因为同样的原因,如果有新的状态以及它对应的行为需要定义时,可以很方便地通过设立新的子类的方式加到系统里,不需要改动其他的类。
  2. 由于每一个状态都被包装到了类里面,就可以不必采用过程性的处理方式,不必使用长篇累牍的条件转移语句。
  3. 使用状态模式使系统状态的变化变得很明显。由于不需要用一些属性来指明系统所处的状态,所以就不用担心修改这些属性不当造成的错误。
  4. 可以在系统的不同部分使用一些相同的状态类的对象,这种共享对象的办法与享元模式相符合。事实上,此时这些状态对象基本上是只有行为而没有内部状态的享元。
  5. 虽然状态模式会造成大量的小型状态类,但是它可以使程序免于大量的条件转移语句,实际上使程序更易于维护。
  6. 系统所选的状态子类均是从一个抽象状态类或接口继承而来,Java语言的特性使得在Java语言中使用状态模式较为安全,多态性是状态模式的核心。

使用场景

  • 对象的行为依赖于它所处的状态,即行为随状态改变而改变的场景。
  • 对象在某个方法中依赖于一重或多重条件分支语句,此时可以使用状态模式将每一个分支语句都包装到一个单独的类中,使得这些条件分支语句能够以类的方式独立存在和演化。如此,维护这些独立的类就不会影响到系统的其他部分。
/** * 频道(抽象状态) */public interface Channel {    //播放频道中的节目    public void display();}/** * 具体状态 */public class CCTV1 implements Channel {    @Override    public void display() {        System.out.println("CCTV1正在播放新闻联播");    }}/** * 具体状态 */public class CCTV2 implements Channel {    @Override    public void display() {        System.out.println("CCTV2正在播放动物世界");    }}/** * 具体状态 */public class CCTV6 implements Channel {    @Override    public void display() {        System.out.println("CCTV6正在播放电影");    }}/** * 电视--环境角色 */public class TV {    private Channel channel1 = new CCTV1();    private Channel channel2 = new CCTV2();    private Channel channel6 = new CCTV6();    //当前频道    private Channel curChanel;    public Channel getCurChanel() {        return curChanel;    }    public void setCurChanel(Channel curChanel) {        this.curChanel = curChanel;    }    public void displayCCTV1(){        this.setCurChanel(channel1);        this.curChanel.display();    }    public void displayCCTV2(){        this.setCurChanel(channel2);        this.curChanel.display();    }    public void displayCCTV6(){        this.setCurChanel(channel6);        this.curChanel.display();    }}public class Main {    public static void main(String[] args) {        TV tv = new TV();        tv.displayCCTV1();        System.out.println("CCTV1播放广告");        tv.displayCCTV2();        System.out.println("就是想换台");        tv.displayCCTV6();    }}

  

转载于:https://www.cnblogs.com/aeolian/p/8952669.html

你可能感兴趣的文章
vue php axios 跨域,在vue中如何使用axios进行跨域处理
查看>>
php 绝对路径变成相对路径,php 相对路径转成绝对路径的实现方法
查看>>
php获取163邮件,用php得到163的邮件信息_PHP教程
查看>>
有限状态机框架php,Leetcode 65 Valid Number DFA有限状态机
查看>>
mysql分页sql语句优化,mysql 百万条数据分页优化
查看>>
php echo斜体,Markdown语言小记
查看>>
java two sum,TwoSum.java
查看>>
php if not exists,mysql防止重复插入相同记录 insert if not exists
查看>>
python 当前时间的零点,python 获取当天凌晨零点的时间戳方法
查看>>
PHP 支付宝自带框架,php接入支付宝接口以及嵌入thinkphp框架
查看>>
oracle序列异常,oracle 序列
查看>>
linux查看文件个数的命令,linux下查看进程打开的文件个数命令
查看>>
linux命令eric,linux修改程序运行优先级命令
查看>>
linux中crS脚本解析,浅谈Linux C语言动态库及静态库
查看>>
linux va_start 编译,C 库宏 – va_start() | 菜鸟教程
查看>>
linux fwrite写入中文,linux的fwrite()使用方法,当前时间写入文本的程序
查看>>
linux rpm deb系,linux deb系 rpm系 配置路由
查看>>
c语言中的16进制坐标计算器,16进制计算器
查看>>
c sftp类库 linux,libssh sftp.c sftp_mkdir函数二次释放漏洞
查看>>
c语言编辑strcmp,C语言实现strcmp
查看>>