设计模式-状态模式(25)

news/2024/7/24 5:58:28 标签: 设计模式, java

定义

状态模式(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


http://www.niftyadmin.cn/n/1409521.html

相关文章

react 修改state为对象中的某一个属性值

针对state为对象,想要修改对象中某一个值而不修改其他值,请欣赏接下来的方法 以前写法 1.设置state对象 state{datavalue:{slid:,name:,memo:,version:,icon:defaultimg,loginlink:,key:,support_game:[],noticelink:,contact:{key:-1,label:},group:{key:,label:},},}2 修改s…

python找到字符中空格所在的位置_Python查找字符在字符串中出现的所有位置

题目出自PTA python编程题3-3 输出字母在字符串中位置索引: 题目:输入一个字符串,再输入两个字符,求这两个字符在字符串中的索引。 输入格式: 第一行输入字符串 第二行输入两个字符,用空格分开。 输出格式: 反向输出字…

ehCache详解

Ehcache中不仅可以用配置文件来配置缓存,而在代码中也可以实现同样的功能。 CacheManager singletonManager CacheManager.create(); Cache memoryOnlyCache new Cache(“testCache”, 50000, false, false, 8, 2); Cache test singletonManager.getCache(“t…

react Antd中使用Tabs组件点击头部,只更新一次问题

在使用tabs使用子模块中数据请求只执行第一次点击该头部时候,后面多次返回之后执行数据无效等问题 可以通过ref对子模块方法进行调用 MenuTab(e)>{console.log(e);this.setState({tabDeafult:e})window.sessionStorage.setItem("rid",e);setTimeout(() > {th…

redis 哨兵_Spring集成Redis哨兵配置

什么是哨兵Sentinel(哨兵)是用于监控Redis集群中Master状态工具,可以监视一个或者多个redis master服务,以及这些master服务的所有从服务;当某个master服务宕机后,会把这个master下的某个服务升级为master来…

TortoiseGit自动记住用户名密码的方法

windows下比较比较好用的git客户端有2种: 1. msysgit TortoiseGit(乌龟git) 2. GitHub for Windows github的windows版也用过一段时间,但还是不太习惯。所以目前仍然青睐与msysgit乌龟git的组合。 TortoiseGit在提交时总数会提示你输入用户名密码&#…

react antd 自定义Pagination 分页功能

antd 自定义Pagination 分页功能,研究明白其实看着很简单 主要就是slice((pagenum-1)*pageSize,(pagenum-1)*pageSizepageSize) {objlistdata.slice((pagenum-1)*pageSize,(pagenum-1)*pageSizepageSize).map((item,index)>{return(<ContentList data{item.data} key{ite…

java 如何检测内在泄漏呢

1、为什么会发生内存泄漏 java 如何检测内在泄漏呢&#xff1f;我们需要一些工具进行检测&#xff0c;并发现内存泄漏问题&#xff0c;不然很容易发生down机问题。 编写java程序最为方便的地方就是我们不需要管理内存的分配和释放&#xff0c;一切由jvm来进行处理&#xff0c;当…