设计模式--状态模式

1.定义

允许对象在内部状态改变时改变它的行为,对象看起来好像是修改了它的类。

2.类图

这里写图片描述

3.状态模式与策略模式区别

  • 状态模式与策略模式拥有相同的类图,都会事先定义好一组类(状态或行为)
  • 状态模式会事先定义一组状态执行的顺序,类经过不同的状态时会有不同的行为,即通过状态的改变来控制类的行为
  • 策略模式不会预先定义状态转换的顺序,通常是通过组合和委托来拥有不同的行为或算法

4.测试代码

此处使用自动售货机的例子作为测试代码
自动售货机有三个状态和三个动作:

  • 状态:已投币状态、未投币状态、商品售罄状态
  • 动作:投币,退币,点击出货

4.1.测试代码类图

这里写图片描述

4.2.代码

4.2.1.状态接口

/**
 * 自动售货机状态接口
 */
public interface State {

    /**
     * 投币
     */
    void insertMoney();

    /**
     * 退币
     */
    void deleteMoney();

    /**
     * 出货
     */
    void soldGoods();
}

4.2.2.已投币状态类

/**
 * 已投币状态
 */
public class HasMoney implements State {
    GoodsMachine goodsMachine;

    HasMoney(GoodsMachine goodsMachine) {
        this.goodsMachine = goodsMachine;
    }

    @Override
    public void insertMoney() {
        System.out.println("已投币状态,不能重复投币");
    }

    @Override
    public void deleteMoney() {
        System.out.println("退币成功");
        goodsMachine.setState(goodsMachine.getNoMoney());
    }

    @Override
    public void soldGoods() {
        System.out.println("出货了,请收好。。。。");
        goodsMachine.setCount(goodsMachine.getCount()-1);
        if(goodsMachine.getCount()>0){
            System.out.println("出货完毕,库存大于0,设置为未投币状态");
            goodsMachine.setState(goodsMachine.getNoMoney());
        }else {
            System.out.println("出货完毕,库存为0,设置为售罄状态");
            goodsMachine.setState(goodsMachine.getSoldOutGoods());
        }
    }

}

4.2.3.未投币状态类

/**
 * 未投币状态
 */
public class NoMoney implements State {
    GoodsMachine goodsMachine;

    NoMoney(GoodsMachine goodsMachine) {
        this.goodsMachine = goodsMachine;
    }

    @Override
    public void insertMoney() {
        System.out.println("投币成功");
        goodsMachine.setState(goodsMachine.getHasMoney());
    }

    @Override
    public void deleteMoney() {
        System.out.println("未投币状态,不能退币");
    }

    @Override
    public void soldGoods() {
        System.out.println("未投币状态,不能出货");
    }
}

4.2.4.售罄状态

/**
 * 售罄状态
 */
public class SoldOutGoods implements State {
    GoodsMachine goodsMachine;

    SoldOutGoods(GoodsMachine goodsMachine) {
        this.goodsMachine = goodsMachine;
    }

    @Override
    public void insertMoney() {
        System.out.println("售罄状态,不能投币");
    }

    @Override
    public void deleteMoney() {
        System.out.println("售罄状态,不能退币");
    }

    @Override
    public void soldGoods() {
        System.out.println("售罄状态,不能出货");
    }

}

4.2.5.售货机类

/**
 * 自动售货机类
 * 内部持有一个状态,可以流转为所有状态
 */
public class GoodsMachine {
    private State hasMoney;
    private State noMoney;
    private State soldOutGoods;

    //售货机初始商品为0
    private int count = 0;
    //售货机初始为售罄状态
    private State state = soldOutGoods;

    GoodsMachine(int count) {
        hasMoney = new HasMoney(this);
        noMoney = new NoMoney(this);
        soldOutGoods = new SoldOutGoods(this);
        this.count = count;
        //商品大于0,将状态初始化为未投币状态
        if (count > 0) {
            this.state = noMoney;
        }
    }
    //投币
    void insertMoney() {
        state.insertMoney();
    }
    //点击出货
    void soldGoods() {
        state.soldGoods();
    }
    //以下为get、set方法
    public State getHasMoney() {return hasMoney;}
    public void setHasMoney(State hasMoney) {this.hasMoney = hasMoney;}
    public State getNoMoney() {return noMoney;}
    public void setNoMoney(State noMoney) {this.noMoney = noMoney;}
    public State getSoldOutGoods() {return soldOutGoods;}
    public void setSoldOutGoods(State soldOutGoods) {this.soldOutGoods = soldOutGoods; }
    public State getState() {return state;}
    public void setState(State state) {this.state = state;}
    public int getCount() {return count;}
    public void setCount(int count) {this.count = count;}
}

4.2.6.测试入口类

public class InitMain {
    public static void main(String[] args) {
        /**
         * 测试自动售货机代码
         * 有三个状态:已投币状态、未投币状态、商品售罄状态
         * 有三个动作:投币,退币,点击出货
         */
        //创建一个有三个商品的自动售货机
        GoodsMachine goodsMachine = new GoodsMachine(3);
        goodsMachine.insertMoney();//投币
        goodsMachine.soldGoods();//点击出货
        goodsMachine.insertMoney();//投币
        goodsMachine.soldGoods();//点击出货
        goodsMachine.insertMoney();//投币
        goodsMachine.soldGoods();//点击出货
        goodsMachine.insertMoney();//投币

    }
}

4.2.7.测试输出及说明

此文中只处理了商品从创建售货机到售罄的状态,没有处理售罄之后重新装入商品的状态,测试代码输出如下:

投币成功
出货了,请收好。。。。
出货完毕,库存大于0,设置为未投币状态
投币成功
出货了,请收好。。。。
出货完毕,库存大于0,设置为未投币状态
投币成功
出货了,请收好。。。。
出货完毕,库存为0,设置为售罄状态
售罄状态,不能投币

5.总结

预先定义一组状态转换(状态流转顺序),通过状态的改变来控制类的行为。至于状态的转换可以在具体状态类中,也可以在容器类中。
如果状态流转放在具体状态类中,则会在状态类之间增加了依赖,如果状态流转放在容器类中,则是尽可能的将状态类之间的依赖降至最低。做这个决策则相当于对开闭原则做决策(对哪个类修改封闭)。
优点:

  • 枚举了所有的状态,每个状态都对应一个类。
  • 可以方便的增加新的状态,改变对象状态即可改变类的行为。
  • 通过状态转换逻辑与状态对象,可以将原有的巨大的语句块拆开。
  • 可以让多个容器(context)对象共享一个状态对象,减少对象个数。

缺点:

  • 会导致设计中新增大量的类。
  • 有点违反开闭原则。
  • 结构与实现都比较复杂,使用不当容易导致代码混乱。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值