设计模式之状态模式

读书笔记:headfirst 设计模式 ,大话设计模式,相关技术博客等


代码案例

用一个大家都熟悉的网购订单状态(简化版)来解释状态模式

首先不使用状态模式时的代码


// 测试类
public class SimpleStateTest {
    public static void main(String[] args) {
        Buyer buyer = new Buyer();
        buyer.setName("小明");
        Saler saler = new Saler();
        saler.setName("王老板");
        // 创建普通订单
        SimpleOrder order = new SimpleOrder("001",buyer, saler);
        // 买家付款
        order.buyerPay();
        // 卖家发货
        order.SalerSendOut();
        // 买家取消订单
        order.BuyerCancel();
        // 买家收货
        order.BuyerReceive();
    }
}

测试结果:
创建新订单 001(买家:小明  卖家:王老板) →当前订单状态为未付款状态 
买家:小明 已付款 →当前订单状态为已付款状态 
卖家:王老板 已发货 →当前订单状态为待收货&已发货状态 
!非法状态 无法取消订单
买家:小明已确认收货 →当前订单状态为已完成状态 


具体代码↓

// 买家
public class Buyer {
    
    private String name;

    public String getName() {
        return "买家:"+name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
}

// 卖家
public class Saler {
    
    private String name;

    public String getName() {
        return "卖家:"+name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
}

// 订类
public class SimpleOrder {

    // 状态订单枚举
    public static enum State {

        NON_PAY("未付款"), PAID("已付款"), RECEIVING("待收货&已发货"), COMPLETED("已完成"), CLOSED("已取消");

        private String name;

        State(String name) {
            this.name = name;
        }

        public String getName() {
            return name + "状态 ";
        }

    }

    // 构造方法 订单号 买家 卖家
    public SimpleOrder(String num, Buyer buyer, Saler saler) {
        this.num = num;
        this.buyer = buyer;
        this.saler = saler;
        System.out.print("创建新订单 " + num + "(" + buyer.getName() + "  " + saler.getName() + ")");
        setOrderState(State.NON_PAY);
    }

    // 订单编号
    private String num;
    // 买家
    private Buyer buyer;
    // 卖家
    private Saler saler;
    // 订单状态
    private State orderState;

    public void setOrderState(State orderState) {
        this.orderState = orderState;
        showState();
    }

    // 买家付款
    public void buyerPay() {

        switch (this.orderState) {
        case NON_PAY:
            System.out.print(buyer.getName() + " 已付款");
            this.setOrderState(State.PAID);
            break;
        case PAID:
            System.out.print(buyer.getName() + " 再次付款");
            break;
        case RECEIVING:
            System.out.print("!非法状态 无法付款");
            break;
        case COMPLETED:
            System.out.print("!非法状态 无法付款");
            break;
        case CLOSED:
            System.out.print("!非法状态 无法付款");
            break;
        default:
            System.out.print("!非法状态 非法状态");
            break;
        }
    }

    // 卖家发货
    public void SalerSendOut() {
        switch (this.orderState) {
        case NON_PAY:
            System.out.print(State.NON_PAY.getName() + saler.getName() + "无法发货");
            this.setOrderState(State.PAID);
            break;
        case PAID:
            System.out.print(saler.getName() + " 已发货");
            this.setOrderState(State.RECEIVING);
            break;
        case RECEIVING:
            System.out.print("!非法状态 无法发货");
            break;
        case COMPLETED:
            System.out.print("!非法状态 无法发货");
            break;
        case CLOSED:
            System.out.print("!非法状态 无法发货");
            break;
        default:
            System.out.print("!非法状态 非法状态");
            break;
        }
    }

    // 买家收货
    public void BuyerReceive() {
        switch (this.orderState) {
        case NON_PAY:
            System.out.print("!非法状态 无法收货");
            break;
        case PAID:
            System.out.print("!非法状态 无法收货");
            break;
        case RECEIVING:
            System.out.print(buyer.getName() + "已确认收货");
            this.setOrderState(State.COMPLETED);
            break;
        case COMPLETED:
            System.out.print("!非法状态 无法收货");
            break;
        case CLOSED:
            System.out.print("!非法状态 无法收货");
            break;
        default:
            System.out.print("!非法状态 无法收货");
            break;
        }
    }

    // 买家取消订单
    public void BuyerCancel() {
        switch (this.orderState) {
        case NON_PAY:
            System.out.print(buyer.getName() + "取消订单");
            this.setOrderState(State.CLOSED);
            break;
        case PAID:
            System.out.print(buyer.getName() + "取消订单 付款金额已退回买家账户");
            this.setOrderState(State.RECEIVING);
            break;
        case RECEIVING:
            System.out.println("!非法状态 无法取消订单");
            break;
        case COMPLETED:
            System.out.print("!非法状态 无法取消订单");
            break;
        case CLOSED:
            System.out.print("!非法状态 无法取消订单");
            break;
        default:
            System.out.print("!非法状态 无法取消订单");
            break;
        }
    }

    // 卖家买家取消订单
    public void SalerCancel() {
        switch (this.orderState) {
        case NON_PAY:
            System.out.print(saler.getName() + "取消订单");
            this.setOrderState(State.CLOSED);
            break;
        case PAID:
            System.out.print(saler.getName() + "取消订单 买家付款金额已退回买家账户");
            this.setOrderState(State.RECEIVING);
            break;
        case RECEIVING:
            System.out.print("!非法状态 无法取消订单");
            break;
        case COMPLETED:
            System.out.print("!非法状态 无法取消订单");
            break;
        case CLOSED:
            System.out.print("!非法状态 无法取消订单");
            break;
        default:
            System.out.print("!非法状态 无法取消订单");
            break;
        }
    }

    // 展示当前订单状态
    private void showState() {
        System.out.print(" →当前订单状态为" + this.orderState.getName());
        System.out.println();
    }

}

PS: 我们看到代码中许多switch(if else),如果现在想加入一个退货中状态会很麻烦,每个判断分支都需要再编写新状态的判断逻辑,状态模式就是解决这个问题的

状态模式

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

  • 面向对象设计其实就是希望做到代码的责任分解
  • 状态模式主要解决的是当控制一个对象状态转换条件的表达式过于复杂的情况,把状态的判断逻辑转移到表示不同状态的一系列状态类当中
  • 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以使用状态模式了

状态模式结构图

  • 状态模式允许一个对象基于内部状态而拥有不同的行为
  • 和程序状态机(PSM)不同,状态模式用类代表状态
  • context会将行为 委托给当前状态对象
  • 通过将每个状态封装进一个类,把以后需要做的任何改变局部化了
  • 通过定义新的状态子类很容易增加新的状态与转换,消除了庞大的条件分支语句
  • 状态模式与策略模式又相同的类图,但是它们的意图不同
  • 策略模式通常会用行为或算法来配置context类
  • 状态模式允许context随着状态改变而改变
  • 状态转换可以由state类或context类控制
  • 状态类可以被多个context实例共享
  • 使用状态模式会导致设计中的类数目大量增加

使用状态模式重新编写代码案例

类图

代码

// 测试类
public class StateTest {

    public static void main(String[] args) {
        Buyer buyer = new Buyer();
        buyer.setName("小明");
        Saler saler = new Saler();
        saler.setName("王老板");
        // 创建使用状态模式的订单
        Order order = new Order("001",buyer, saler);
        // 买家付款
        order.buyerPay();
        // 卖家发货
        order.SalerSendOut();
        // 买家取消订单
        order.BuyerCancel();
        // 买家收货
        order.BuyerReceive();
    }
}

结果:
创建新订单 001(买家:小明  卖家:王老板) →当前订单状态为未付款
买家:小明 已付款 →当前订单状态为已付款
卖家:王老板 已发货 →当前订单状态为收货中
!收货中:买家:小明无法取消订单 可以选择退货
买家:小明已收货 →当前订单状态为已完成


//订单
public class Order {
    
    //未付款
    public static final NonPay NON_PAY= new NonPay();
    //已付款
    public static final Paid PAID = new Paid();
    //待收货&已发货
    public static final Receiving RECEIVING = new Receiving();
    // 已完成
    public static final Completed COMPLETED = new Completed();
    // 已取消
    public static final Closed CLOSED = new Closed();

    public Order(String num,Buyer buyer, Saler saler ) {
        this.num =num;
        this.buyer = buyer;
        this.saler = saler;
        System.out.print("创建新订单 "+num+"("+buyer.getName() +"  "+saler.getName()+")");
        setOrderState(NON_PAY);
    }
    
    //订单编号
    private String num;
    // 买家
    private Buyer buyer;
    // 卖家
    private Saler saler;
    // 订单状态
    private OrderState orderState;

    public void setOrderState(OrderState orderState) {
        this.orderState = orderState;
        showState();
    }
    // 卖家付款
    public void buyerPay() {
        orderState.pay(this, buyer);
    }
    // 卖家发货
    public void SalerSendOut() {
        orderState.sendOut(this, saler);
    }
    // 买家收货
    public void BuyerReceive() {
        orderState.receive(this, buyer);
    }
    // 买家取消订单
    public void BuyerCancel() {
        orderState.cancel(this, buyer);
    }
    // 卖家买家取消订单
    public void SalerCancel() {
        orderState.cancel(this, saler);
    }
    // 展示当前订单状态
    private void showState() {
        System.out.print(" →当前订单状态为" + orderState.getStateName());
        System.out.println();
    }
    
}

// 订单状态接口
public interface OrderState {
    // 获取状态名称
    String getStateName();
    // 买家付款
    void pay(Order order,Buyer buyer);
    // 卖家发货
    void sendOut(Order order,Saler saler);
    // 买家收货
    void receive(Order order,Buyer buyer);
    // 买家取消订单
    void cancel(Order order,Buyer buyer);
    // 卖家取消订单
    void cancel(Order order,Saler saler);
    // 买家退货
    void sendOut(Order order,Buyer buyer);
    // 卖家收货
    void receive(Order order,Saler saler);
}

// 未付款
public class NonPay implements OrderState {

    @Override
    public String getStateName() {
        return "未付款";
    }

    @Override
    public void pay(Order order, Buyer buyer) {
        System.out.print(buyer.getName() + " 已付款");
        order.setOrderState(Order.PAID);
    }

    @Override
    public void sendOut(Order order, Saler saler) {
        System.out.println("未付款状态 " + saler.getName() + "无法发货");
    }

    @Override
    public void receive(Order order, Buyer buyer) {
        System.out.println("未付款状态 " + buyer.getName() + "无法收货");
    }

    @Override
    public void cancel(Order order, Buyer buyer) {
        System.out.println(buyer.getName()+" 取消了订单,订单被关闭");
        order.setOrderState(Order.CLOSED);
    }

    @Override
    public void cancel(Order order, Saler saler) {
        System.out.println(saler.getName()+" 取消了订单,订单被关闭");
        order.setOrderState(Order.CLOSED);
    }

    @Override
    public void sendOut(Order order, Buyer buyer) {
        System.out.println("未付款状态 " + buyer.getName() + "无法退货");

    }

    @Override
    public void receive(Order order, Saler saler) {
        System.out.println("未付款状态 " + saler.getName() + "无法确认收到退货");
    }

}

// 已付款
public class Paid implements OrderState {

    @Override
    public String getStateName() {
        return "已付款";
    }

    @Override
    public void pay(Order order, Buyer buyer) {
        System.out.println(buyer.getName()+"再次付款");
    }

    @Override
    public void sendOut(Order order, Saler saler) {
        System.out.print(saler.getName()+" 已发货");
        order.setOrderState(Order.RECEIVING);
    }

    @Override
    public void receive(Order order, Buyer buyer) {
        System.out.println("卖家未发货 "+buyer.getName()+"无法收货");
    }

    @Override
    public void cancel(Order order, Buyer buyer) {
        System.out.println("!"+buyer.getName()+"取消订单 已付款金额会退回买家账户");
        order.setOrderState(Order.CLOSED);
    }

    @Override
    public void cancel(Order order, Saler saler) {
        System.out.println("!"+saler.getName()+"取消订单 已付款金额会退回买家账户");
        order.setOrderState(Order.CLOSED);
    }

    @Override
    public void sendOut(Order order, Buyer buyer) {
        System.out.println(buyer.getName()+"无法执行退货");
    }

    @Override
    public void receive(Order order, Saler saler) {
        System.out.println(saler.getName()+"无法执行确认收到退货");

    }

}

// 收货中
public class Receiving implements OrderState {

    @Override
    public String getStateName() {
        return "收货中";
    }

    @Override
    public void pay(Order order, Buyer buyer) {
        System.out.println(buyer.getName()+"无法再次付款");
    }

    @Override
    public void sendOut(Order order, Saler saler) {
        System.out.println(saler.getName()+"无法再次发货");

    }

    @Override
    public void receive(Order order, Buyer buyer) {
        System.out.print(buyer.getName()+"已收货");
        order.setOrderState(Order.COMPLETED);
    }

    @Override
    public void cancel(Order order, Buyer buyer) {
        System.out.println("!"+getStateName()+":"+buyer.getName()+"无法取消订单 可以选择退货");
    }

    @Override
    public void cancel(Order order, Saler saler) {
        System.out.println("!"+getStateName()+":"+saler.getName()+"无法取消订单");
    }

    @Override
    public void sendOut(Order order, Buyer buyer) {
        System.out.println(getStateName()+":"+buyer.getName()+"无法发货");

    }

    @Override
    public void receive(Order order, Saler saler) {
        System.out.println(getStateName()+":"+saler.getName()+"无法确认收到退货");

    }

}

// 已完成
public class Completed implements OrderState {

    @Override
    public String getStateName() {
        return "已完成";
    }

    @Override
    public void pay(Order order, Buyer buyer) {
        System.out.println("订单已完成 无法付款");

    }

    @Override
    public void sendOut(Order order, Saler saler) {
        System.out.println("订单已完成 无法发货");

    }

    @Override
    public void receive(Order order, Buyer buyer) {
        System.out.println("订单已完成 无法收货");

    }

    @Override
    public void cancel(Order order, Buyer buyer) {
        System.out.println("订单已完成 无法取消");

    }

    @Override
    public void cancel(Order order, Saler saler) {
        System.out.println("订单已完成 无法取消");

    }

    @Override
    public void sendOut(Order order, Buyer buyer) {
        System.out.println("订单已完成 无法退货");
    }

    @Override
    public void receive(Order order, Saler saler) {
        System.out.println("订单已完成 无法确认收到退货");
    }

}

// 已取消
public class Closed implements OrderState {

    @Override
    public String getStateName() {
        return "已关闭";
    }

    @Override
    public void pay(Order order, Buyer buyer) {
        System.out.println("订单已关闭 无法付款");
    }

    @Override
    public void sendOut(Order order, Saler saler) {
        System.out.println("订单已关闭 无法发货");
    }

    @Override
    public void receive(Order order, Buyer buyer) {
        System.out.println("订单已关闭 无法收货");
    }

    @Override
    public void cancel(Order order, Buyer buyer) {
        System.out.println("订单已关闭 无法取消");
    }

    @Override
    public void cancel(Order order, Saler saler) {
        System.out.println("订单已关闭 无法取消");
    }

    @Override
    public void sendOut(Order order, Buyer buyer) {
        System.out.println("订单已关闭 无法退货");
    }

    @Override
    public void receive(Order order, Saler saler) {
        System.out.println("订单已关闭 无法确认收到退货");
    }

}

你可能感兴趣的:(笔记,读书笔记,设计模式,状态模式)