21.状态模式

1.什么是状态模式?

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

举个例子:水在不同的温度下会有不同状态,也能表现出不同特性。看起来不一样,其实本质上它还是水

 

状态模式又叫状态对象,它是一种对象行为型模式。

 

2.状态模式结构

(1)Context(环境类)又叫上下文类,拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。

(2)State(抽象状态类)它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以卸载抽象状态类中

(3)ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类的行为有所不同。

 

3.状态模式的实现

(1)环境类

/**
 * 环境类
 */
public class Context {
    private State state;//维持一个对抽象状态对象的引用
    private int value;//其他属性值,该属性值的变化可能会导致对象的状态发生变化

    public int getValue() {
        return value;
    }

    //设置状态对象
    public void setState(State state){
        this.state = state;
    }

    public void request(){
        //其他代码
        state.handle();//调用状态对象的业务方法
        //其他代码
    }

    public void changeState(){
        //判断属性值,根据属性值进行状态转换
        if(value == 0){
            this.setState(new ConcreteState());
        }else if(value == 1){
            this.setState(new ConcreteState());
        }
    }
}

(2)抽象状态类

/**
 * 抽象状态类
 */
public abstract class State {
    //声明抽象业务方法,不同的具体状态类可以有不同的实现
    public abstract void handle();
}

(3)具体状态类

/**
 * 具体状态类
 */
public class ConcreteState extends State {
    @Override
    public void handle() {
        //方法的具体实现代码
    }
}

(4)状态变更

public class StateChange {
    public void changeState(Context context){
        //判断属性值,根据属性值进行状态转换
        if(context.getValue() == 0){
            context.setState(new ConcreteState());
        }else if(context.getValue() == 1){
            context.setState(new ConcreteState());
        }
    }
}

 

4.状态模式实例——银行账户随余额不同有不同状态

(1)账户状态类,充当抽象状态类

/**
 * 账户状态类,充当抽象状态类
 */
public abstract class AccountState {
    protected Account acc;

    public abstract void deposit(double amount);
    public abstract void withdraw(double amount);
    public abstract void computeInterest();
    public abstract void stateCheck();
}

(2)正常状态类,充当具体状态类

/**
 * 正常状态类,充当具体状态类
 */
public class NormalState extends AccountState {
    public NormalState(Account acc){
        this.acc = acc;
    }

    public NormalState(AccountState state){
        this.acc = state.acc;
    }

    @Override
    public void deposit(double amount) {
        acc.setBalance(acc.getBalance()+amount);
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        acc.setBalance(acc.getBalance()-amount);
        stateCheck();
    }

    @Override
    public void computeInterest() {
        System.out.println("正常状态,无需支付利息");
    }

    //状态转换
    @Override
    public void stateCheck() {
        if(acc.getBalance() > -2000 && acc.getBalance() <= 0){
            acc.setState(new OverdraftState(this));
        }else if(acc.getBalance() == -2000){
            acc.setState(new RestrictedState(this));
        }else if(acc.getBalance() < -2000){
            System.out.println("操作受限");
        }
    }
}

(3)透支状态类,充当具体状态类

/**
 * 透支状态类,充当具体状态类
 */
public class OverdraftState extends AccountState {
    public OverdraftState(Account acc){
        this.acc = acc;
    }

    public OverdraftState(AccountState state){
        this.acc = state.acc;
    }

    @Override
    public void deposit(double amount) {
        acc.setBalance(acc.getBalance()+amount);
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        acc.setBalance(acc.getBalance()-amount);
        stateCheck();
    }

    @Override
    public void computeInterest() {
        System.out.println("计算利息");
    }

    @Override
    public void stateCheck() {
        if(acc.getBalance() > 0){
            acc.setState(new NormalState(this));
        }else if(acc.getBalance() == -2000){
            acc.setState(new RestrictedState(this));
        }else if(acc.getBalance() < -2000){
            System.out.println("操作受限");
        }
    }
}

(4)受限状态类,充当具体状态类

/**
 * 受限状态类,充当具体状态类
 */
public class RestrictedState extends AccountState {
    public RestrictedState(Account acc){
        this.acc = acc;
    }

    public RestrictedState(AccountState state){
        this.acc = state.acc;
    }

    @Override
    public void deposit(double amount) {
        acc.setBalance(acc.getBalance()+amount);
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        System.out.println("账号受限,取款失败");
    }

    @Override
    public void computeInterest() {
        System.out.println("计算利息");
    }

    @Override
    public void stateCheck() {
        if(acc.getBalance() > 0){
            acc.setState(new NormalState(this));
        }else if(acc.getBalance() > -2000){
            acc.setState(new OverdraftState(this));
        }
    }
}

(5)银行账户,充当环境类

/**
 * 银行账户,充当环境类
 */
public class Account {
    private AccountState state;//维持一个对抽象状态对象的引用
    private String owner;//开户名
    private double balance = 0;//账户余额

    public Account(String owner ,double init){
        this.owner = owner;
        this.balance = balance;
        this.state = new NormalState(this);//设置初始状态
        System.out.println(this.owner+"开户,初始金额"+init);
        System.out.println("----------------");
    }

    public void deposit(double amount){
        System.out.println(this.owner+"存款"+amount);
        state.deposit(amount);//调用状态对象的deposit()方法
        System.out.println("现在余额为:"+this.balance);
        System.out.println("现在账户状态为:"+this.state.getClass().getName());
        System.out.println("----------------");
    }

    public void withdraw(double amount){
        System.out.println(this.owner+"取款"+amount);
        state.withdraw(amount);//调用状态对象的withdraw()方法
        System.out.println("现在余额为:"+this.balance);
        System.out.println("现在账户状态为:"+this.state.getClass().getName());
        System.out.println("----------------");
    }

    public void computeInterest(){
        state.computeInterest();//调用状态对象的computeInterest方法
    }

    public AccountState getState() {
        return state;
    }

    public void setState(AccountState state) {
        this.state = state;
    }

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        this.owner = owner;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
}

(6)客户端类

public class Client {
    public static void main(String[] args) {
        Account account = new Account("段誉",0.0);
        account.deposit(1000);
        account.withdraw(2000);
        account.deposit(3000);
        account.withdraw(4000);
        account.withdraw(1000);
        account.computeInterest();
    }
}

(7)路径及结果

 

5.共享状态

在有些情况下,多个环境对象可能需要共享一个状态,如果希望在系统中实现多个环境对象共享一个或多个状态对象,那么需要将这些状态对象定义为环境类的静态成员变量。

实例——两个开关要么同时开,要么同时关

(1)开关类

/**
 * 开关类
 */
public class Switch {
    private static SwitchState currentState,onState,offState;//定义3个静态的状态对象
    private String name;

    public Switch(String name){
        this.name = name;
        onState = new OnState();
        offState = new OffState();
        currentState = onState;
    }

    public void setState(SwitchState state){
        currentState = state;
    }

    public static SwitchState getState(String type){
        if(type.equalsIgnoreCase("on")){
            return onState;
        }else {
            return offState;
        }
    }

    //打开开关
    public void on(){
        System.out.println(name);
        currentState.on(this);
    }

    //关闭开关
    public void off(){
        System.out.println(name);
        currentState.off(this);
    }
}

(2)抽象状态类

/**
 * 抽象状态类
 */
public abstract class SwitchState {
    public abstract void on(Switch s);
    public abstract void off(Switch s);
}

(3)打开状态类

/**
 * 打开状态类
 */
public class OnState extends SwitchState {
    @Override
    public void on(Switch s) {
        System.out.println("已经打开");
    }

    @Override
    public void off(Switch s) {
        System.out.println("关闭");
        s.setState(s.getState("off"));
    }
}

(4)关闭状态类

/**
 * 关闭状态类
 */
public class OffState extends SwitchState {
    @Override
    public void on(Switch s) {
        System.out.println("打开");
        s.setState(s.getState("on"));
    }

    @Override
    public void off(Switch s) {
        System.out.println("关闭");

    }
}

(5)客户端

public class Client {
    public static void main(String[] args) {
        Switch s1,s2;
        s1 = new Switch("开关1");
        s2 = new Switch("开关2");

        s1.on();
        s2.on();
        s1.off();
        s2.off();
        s2.on();
        s1.on();
    }
}

(6)输出结果及路径

 

6.使用环境类实现状态转换

客户端其实不关心状态类,将状态的转换工作交给具体状态类或环境类来完成,对客户端透明。

实例——第一次单机“放大镜”,屏幕放大一倍。再单击,再放大一倍。再点击,恢复原来大小

(1)屏幕类:环境类

/**
 * 屏幕类:环境类
 */
public class Screen {

    //枚举所有的状态,currentState表示当前状态
    private ScreenState currentState,normalState,largeState,largestState;

    public Screen(){
        this.normalState = new NormalState();//正常状态对象
        this.largeState = new LargeState();//二倍放大状态对象
        this.largestState = new LargestState();//四倍大状态对象
        this.currentState = normalState;//设置初始状态
        this.currentState.display();
    }

    public void setState(ScreenState state){
        this.currentState = state;
    }

    //单机事件处理方法,封装了对状态类中业务方法的调用的状态的转换
    public void onClick(){
        if (this.currentState == normalState){
            this.setState(largeState);
            this.currentState.display();
        }else if (this.currentState == largeState){
            this.setState(largestState);
            this.currentState.display();
        }else if (this.currentState == largestState){
            this.setState(normalState);
            this.currentState.display();
        }
    }
}

(2)屏幕状态类:抽象状态类

/**
 * 屏幕状态类:抽象状态类
 */
public abstract class ScreenState {
    public abstract void display();
}

(3)正常状态类:具体状态类

/**
 * 正常状态类:具体状态类
 */
public class NormalState extends ScreenState {
    @Override
    public void display() {
        System.out.println("正常大小");
    }
}

(4)二倍状态类:具体状态类

/**
 * 二倍状态类:具体状态类
 */
public class LargeState extends ScreenState {
    @Override
    public void display() {
        System.out.println("二倍大小!");
    }
}

(5)四倍状态类:具体状态类

/**
 * 四倍状态类:具体状态类
 */
public class LargestState extends ScreenState {
    @Override
    public void display() {
        System.out.println("四倍大小!");
    }
}

(6)客户端

public class Client {
    public static void main(String[] args) {
        Screen screen = new Screen();
        screen.onClick();
        screen.onClick();
        screen.onClick();
    }
}

(7)输出结果及路径

 

7.状态模式优缺点

优:

(1)状态模式封装了状态的转换规则,将转换代码封装在环境类中或者具体状态类中,而不是分散在业务代码里

(2)状态模式将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为

(3)状态模式允许状态逻辑与状态对象合成一体

(4)让多个环境对象共享一个状态对象

 

缺:

(1)增加类和对象个数,增加开销

(2)设计较为复杂

 

8.使用环境

(1)对象的行为依赖于它的状态

(2)包含大量与对象状态相关的条件语句

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹏哥哥啊Aaaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值