当前位置: 首页 > article >正文

设计模式の状态策略责任链模式

文章目录

  • 前言
  • 一、状态模式
  • 二、策略模式
  • 三、责任链模式


前言

  本篇是关于设计模式中的状态模式、策略模式、以及责任链模式的学习笔记。


一、状态模式

  状态模式是一种行为设计模式,核心思想在于,使某个对象在其内部状态改变时,改变该对象的行为,使对象看起来像是改变了其类。将状态的相关行为封装到独立的状态类中,并通过在运行时切换状态对象来改变对象的行为。实现方式在于,将状态抽取成单独的类,并由上下文类统一管理。
  状态模式的结构包括以下几个主要角色:

  1. 上下文类:它维护一个当前状态的实例,并且对客户端公开其接口。
  2. 抽象状态类:定义了所有具体状态类需要实现的接口,抽取出所有状态下共有的方法。
  3. 具体状态类:实现了抽象状态类,根据自身状态的特点,有选择性第重写父类方法的逻辑。

  假设需要设计一个抽奖系统,有四种状态:

  • 不能抽奖的状态
  • 可以抽奖的状态
  • 发放奖品的状态
  • 奖品发放完成的状态

  状态流转方式如下:
在这里插入图片描述  体现在代码上,首先设计一个抽象状态接口,该接口将各种状态下可能的操作进行聚合:

/**
 * 状态接口
 * 将各种状态下可能的操作聚合成一个接口
 * 实现类根据各自状态可能的业务去重写其中的方法
 */
public interface State {

    /**
     * 扣除积分
     */
    void deduceMoney();

    /**
     * 抽奖
     * @return
     */
    boolean raffle();

    /**
     * 发放奖品
     */
    void dispensePrice();
}

  抽象接口具体的实现
  不能抽奖状态,在此状态下只能去做出扣减积分的操作,扣减完成积分后,状态会变更为可抽奖状态

/**
 * 不能抽奖的状态
 */
public class NoRaffleState implements State{

    RaffleActivity raffleActivity;

    public NoRaffleState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }

    /**
     * 扣除积分
     */
    @Override
    public void deduceMoney() {
        System.out.println("扣除50积分,可以抽奖");
        raffleActivity.setState(raffleActivity.getCanRaffleState());
    }

    /**
     * 抽奖
     *
     * @return
     */
    @Override
    public boolean raffle() {
        System.out.println("扣除积分方能抽奖");
        return false;
    }

    /**
     * 发放奖品
     */
    @Override
    public void dispensePrice() {
        System.out.println("不能发放奖品");
    }
}

  可抽奖状态,只能进行抽奖操作:

  • 未抽中奖品,重新回到不可抽奖状态
  • 抽中了奖品,流转到发送奖品状态
/**
 * 可以抽奖的状态
 */
public class CanRaffleState implements State{

    RaffleActivity raffleActivity;

    public CanRaffleState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }


    /**
     * 扣除积分
     */
    @Override
    public void deduceMoney() {
        System.out.println("已经扣除积分,可以抽奖");
    }

    /**
     * 抽奖
     *
     * @return
     */
    @Override
    public boolean raffle() {
        System.out.println("正在抽奖,请稍等");
        int num = new Random().nextInt(10);
        if (num == 0){
            //中奖了,发放奖品
            raffleActivity.setState(raffleActivity.getDispenseState());
            return true;
        }else {
            System.out.println("很遗憾,您没有中奖");
            //回到不能抽奖的状态
            raffleActivity.setState(raffleActivity.getNoRaffleState());
            return false;
        }
    }

    /**
     * 发放奖品
     */
    @Override
    public void dispensePrice() {
        System.out.println("没中奖,不能发放奖品");
    }
}

  发放奖品状态,只能进行发放奖品的操作:

  • 奖品数量充足,流转到奖品发送完成状态。
  • 奖品数量不足,改变状态为不能抽奖
/**
 * 发放奖品的状态
 */
public class DispenseState implements State{

    RaffleActivity raffleActivity;

    public DispenseState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }

    /**
     * 扣除积分
     */
    @Override
    public void deduceMoney() {
        System.out.println("不能扣除积分");
    }

    /**
     * 抽奖
     *
     * @return
     */
    @Override
    public boolean raffle() {
        System.out.println("不能抽奖");
        return false;
    }

    /**
     * 发放奖品
     */
    @Override
    public void dispensePrice() {
        if (raffleActivity.getCount()>0){
            System.out.println("恭喜中奖了");
            //改变状态为不能抽奖
            raffleActivity.setState(raffleActivity.getNoRaffleState());
        }else {
            System.out.println("很遗憾,奖品发送完了");
            //改变状态为奖品发送完成
            raffleActivity.setState(raffleActivity.getDispenseOutState());
        }

    }
}

  奖品发放完成,则不可以进行任何操作

/**
 * 奖品发放完成的状态
 */
public class DispenseOutState implements State{

    RaffleActivity raffleActivity;

    public DispenseOutState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }

    /**
     * 扣除积分
     */
    @Override
    public void deduceMoney() {
        System.out.println("奖品发送完了,请下次再参加");
    }

    /**
     * 抽奖
     *
     * @return
     */
    @Override
    public boolean raffle() {
        System.out.println("奖品发送完了,请下次再参加");
        return false;
    }

    /**
     * 发放奖品
     */
    @Override
    public void dispensePrice() {
        System.out.println("奖品发送完了,请下次再参加");
    }
}

  创建一个上下文类,对状态进行统一管理,同时对状态进行初始化,并且上面的具体状态类,也聚合了上下文类的对象:

/**
 * 抽奖的行为
 */
public class RaffleActivity {

    /**
     * 初始的状态
     */
    State state = null;

    /**
     * 初始的数量
     */
    int count = 0;

    State canRaffleState = new CanRaffleState(this);
    State noRaffleState = new NoRaffleState(this);
    State dispenseOutState = new DispenseOutState(this);
    State dispenseState = new DispenseState(this);

    public RaffleActivity(int count) {
        //初始状态,不能抽奖
        this.state = getNoRaffleState();
        this.count = count;
    }

    /**
     * 扣除积分
     */
    public void deduceMoney(){
        state.deduceMoney();
    }

    /**
     * 抽奖
     */
    public void raffle(){
        if (state.raffle()){
            //领取奖品
            state.dispensePrice();
        }
    }


    public State getState() {
        return state;
    }

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

    public int getCount() {
        int curCount = this.count;
        count--;
        return curCount;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public State getCanRaffleState() {
        return canRaffleState;
    }

    public void setCanRaffleState(State canRaffleState) {
        this.canRaffleState = canRaffleState;
    }

    public State getNoRaffleState() {
        return noRaffleState;
    }

    public void setNoRaffleState(State noRaffleState) {
        this.noRaffleState = noRaffleState;
    }

    public State getDispenseOutState() {
        return dispenseOutState;
    }

    public void setDispenseOutState(State dispenseOutState) {
        this.dispenseOutState = dispenseOutState;
    }

    public State getDispenseState() {
        return dispenseState;
    }

    public void setDispenseState(State dispenseState) {
        this.dispenseState = dispenseState;
    }
}
public class Client {
    public static void main(String[] args) {
        RaffleActivity raffleActivity = new RaffleActivity(1);

        for (int i = 0; i < 3; i++) {
            //扣积分
            raffleActivity.deduceMoney();
            //抽奖
            raffleActivity.raffle();
        }
    }
}

小结
状态模式的优缺点
优点:

  • 遵循单一职责原则:将与状态相关的代码封装到独立类中。
  • 开闭原则:添加新状态非常方便,无需修改现有代码。
  • 消除大量条件语句:状态切换通过对象替换实现,而非复杂的条件判断。

缺点:

  • 类的数量增加:每个状态都需要创建一个类,可能导致类数量增多。
  • 状态之间的耦合:状态类之间可能需要频繁切换,会导致一定程度的耦合。

二、策略模式

  策略模式是一种行为设计模式,核心思想在于,定义了一组算法,将每个算法封装到独立的类中,使它们可以相互替换。
  策略模式通常包括以下角色:

  1. 上下文类:持有一个策略对象的引用,并且初始化具体策略。
  2. 抽象策略类:定义了所有具体策略类需要实现的接口。
  3. 具体策略类:实现抽象策略类,包含具体的算法或行为。

  假设目前有一个方法,需要根据参数中传入的不同的业务类型,执行不同业务的分派,如果使用传统方式,则会利用switch或者if-else实现,将来需要扩展的时候,需要对分支代码进行修改:

/**
 * 业务处理接口
 */
public interface BusinessClass {

    /**
     * 处理业务
     */
    void handleBusiness(int type);
}
public class BusinessClassImpl implements BusinessClass{


    /**
     * 处理业务
     * 根据传入的参数进行分发
     */
    @Override
    public void handleBusiness(int type) {

        switch (type){
            case 1:
                this.handleBusiness1();
                break;
            case 2:
                this.handleBusiness2();
                break;
            case 3:
                this.handleBusiness3();
                break;
            default:
                break;
        }
    }

    private void handleBusiness3() {
        System.out.println("业务3的具体逻辑");
    }

    private void handleBusiness2() {
        System.out.println("业务2的具体逻辑");
    }

    private void handleBusiness1() {
        System.out.println("业务1的具体逻辑");
    }
}

  使用策略模式改造,则可以抽取一个策略接口

/**
 * 业务策略接口
 */
public interface BusinessStrategy {

    /**
     * 处理具体的业务逻辑
     */
    void handleBusiness();
}

  将传统方式中,每个分支中的方法都抽取到一个单独的类中,实现策略接口

public class Business1 implements BusinessStrategy{
    /**
     * 处理具体的业务逻辑
     */
    @Override
    public void handleBusiness() {
        System.out.println("处理业务逻辑1");
    }
}
public class Business2 implements BusinessStrategy{
    /**
     * 处理具体的业务逻辑
     */
    @Override
    public void handleBusiness() {
        System.out.println("处理业务逻辑2");
    }
}
public class Business3 implements BusinessStrategy{
    /**
     * 处理具体的业务逻辑
     */
    @Override
    public void handleBusiness() {
        System.out.println("处理业务逻辑3");
    }
}

  在上下文类中,对其进行统一的管理,业务代码只需要注入上下文类,调用其中的方法即可。

public class Context {

    private Map<Integer, BusinessStrategy> strategyMap = new HashMap<>();

    /**
     * 初始化上下文,k业务类型 v 业务类型具体的逻辑
     */
    public Context(){
        strategyMap.put(1, new Business1());
        strategyMap.put(2, new Business2());
        strategyMap.put(3, new Business3());
    }

    /**
     * 处理业务
     * 根据传入的参数进行分发
     */
    public void handleBusiness(int type) {
        BusinessStrategy strategy = strategyMap.get(type);
        if (strategy != null) {
            strategy.handleBusiness();
        } else {
            System.out.println("无效的业务类型");
        }
    }
}

小结
策略模式的优缺点
优点:

  • 遵循开闭原则:添加新策略无需修改现有代码,只需扩展新策略类。
  • 消除条件语句:避免了复杂的 if-else 或 switch-case 语句。
  • 提高灵活性:客户端可以动态选择策略。

缺点:

  • 类数量增加:每种策略需要创建一个类,可能导致类的数量过多。
  • 客户端需要了解不同策略:客户端必须知道有哪些策略才能选择合适的策略。

三、责任链模式

  责任链模式是一种行为设计模式,核心目的在于,将请求的处理责任沿着一条链传递,直到有对象处理这个请求为止。责任链模式将请求的发送者和接收者解耦,且可以动态地调整链条上的处理顺序。
  责任链模式通常包含以下角色:

  1. 抽象处理者:定义了处理请求的接口,以及一个指向下一个处理者的引用。(即将自身作为属性存放在类中)
  2. 具体处理者:继承了抽象处理者,具体去实现各自处理请求的逻辑,以及无法处理时/处理完成时,应该调用的下一个处理者
  3. 客户端:创建并组装责任链,通常会将请求发送给责任链的首个处理者

  下面来看一个案例:假设某个学校,购买教材,器材,根据金额不同,需要审批的级别也不同。
  首先构建一个请求对象

public class Request {

    /**
     * 请求id
     */
    protected int id = 0;

    /**
     * 价格
     */
    protected int price = 0;

    public Request() {
    }

    public Request(int id, int price) {
        this.id = id;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

  然后定义一个抽象处理者

/**
 * 抽象审批人
 */
public abstract class Approver {

    /**
     * 审批人名称
     */
    protected String name;

    /**
     * 持有自己的引用
     */
    protected Approver approver;

    public Approver() {
    }

    public Approver(String name) {
        this.name = name;
    }

    public void setApprover(Approver approver) {
        this.approver = approver;
    }

    /**
     * 子类具体去实现处理请求的逻辑
     * @param request
     */
    abstract void handleReq(Request request);

}

  定义具体处理人,继承抽象处理人,编写自己处理的判断逻辑:

public class TeachingDirector extends Approver{


    public TeachingDirector(String name){
        super(name);
    }

    /**
     * 子类具体去实现处理请求的逻辑
     *
     * @param request
     */
    @Override
    void handleReq(Request request) {
        if (request.getPrice()<= 5000){
            System.out.println("请求编号"+ request.id + "已经被" + name + "处理");
        }else {
            approver.handleReq(request);
        }
    }
}
public class Dean extends Approver{

    public Dean(String name){
        super(name);
    }

    /**
     * 子类具体去实现处理请求的逻辑
     *
     * @param request
     */
    @Override
    void handleReq(Request request) {
        if (request.getPrice()<= 10000){
            System.out.println("请求编号"+ request.id + "已经被" + name + "处理");
        }else {
            approver.handleReq(request);
        }
    }
}
public class Principal extends Approver{

    public Principal(String name){
        super(name);
    }

    /**
     * 子类具体去实现处理请求的逻辑
     *
     * @param request
     */
    @Override
    void handleReq(Request request) {
        if (request.getPrice()<= 20000){
            System.out.println("请求编号"+ request.id + "已经被" + name + "处理");
        }else {
            approver.handleReq(request);
        }
    }
}

  最后由客户端对其进行统一组装:

public class Client {
    public static void main(String[] args) {

        Request request = new Request(1, 8000);

        Dean dean = new Dean("院长");
        TeachingDirector teachingDirector = new TeachingDirector("教学主任");
        Principal principal = new Principal("校长");
        //设置下一个审批者
        teachingDirector.setApprover(dean);
        dean.setApprover(principal);
        principal.setApprover(teachingDirector);

        //8000 教学主任处理不了,交给下一级(院长)处理
        teachingDirector.handleReq(request);
    }
}

小结
责任链模式的优缺点

优点:

  • 降低耦合度:请求发送者与接收者解耦,无需关心由谁处理请求。
  • 动态灵活:可以在运行时动态调整责任链的结构。
  • 增强扩展性:新增处理者无需修改现有代码。

缺点:

  • 链条可能过长:请求可能需要经过多个处理者,性能可能受影响。
  • 调试困难:由于请求的处理流程不明确,可能导致调试复杂。


http://www.kler.cn/a/463599.html

相关文章:

  • 基于51单片机和16X16LED点阵屏(74HC138和74HC595驱动)的小游戏《贪吃蛇》
  • Java重要面试名词整理(十八):Sentinel
  • BP神经网络的反向传播算法
  • 迟来的前端面试经验
  • 等保测评和密评的相关性和区别
  • 基于深度学习算法的AI图像视觉检测
  • 【漫话机器学习系列】027.混淆矩阵(confusion matrix)
  • 计算机网络•自顶向下方法:DHCP、NAT、IPV6
  • 大模型WebUI:Gradio全解系列8——Additional Features:补充特性(下)
  • 如何将vCenter6.7升级7.0?
  • vSAN手动平衡磁盘
  • 对比一下Java和go的unsafe包
  • 【电路笔记】-德摩根定理
  • pycharm+anaconda创建项目
  • 短视频矩阵系统前端搭建技术解析,支持OEM
  • React之从0开始(1)
  • Nginx搭建Web网站
  • 玩转树莓派Pico(21): 迷你气象站7——软件整合改进2
  • 基于SSM(Spring + Spring MVC + MyBatis)框架的旅游资源网站
  • git reset --hard(重置到当前提交,所有未提交的更改都会被永久丢弃)
  • ubuntu中zlib安装的步骤是什么
  • 运维人员的Go语言学习路线
  • 初学stm32---高级定时器输出n个pwm波
  • 无人机无法返航紧急处理方式!
  • Redis - 1 ( 11000 字 Redis 入门级教程 )
  • Linux性能优化-网络篇-NAT详解