详解Java实现设计模式之责任链模式

详解Java实现设计模式之责任链模式

一、概述

责任链模式(Chain of Responsibility Pattern)是一种对象行为型设计模式,其作用是减少请求发送者与接收者之间的耦合,通过使多个对象都有机会处理请求来解决请求的发送者和接收者之间的耦合关系。通常情况下,每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,它会把相同的请求传递给下一个接收者,以此类推,形成责任链。

二、优缺点

优点:

  1. 多个对象可以处理同一个请求,具有很好的灵活性和扩展性。
  2. 请求的发送者和接收者解耦,两者不存在直接关联。
  3. 更好的封装性和可维护性,责任链只需要关心自己的处理对象,不关心其他对象。

缺点:

  1. 责任链长度过长,可能会影响责任链传递的效率。
  2. 如果责任链节点没有被正确配置,可能会造成循环调用或者死循环,导致系统崩溃。

三、示例说明

示例一

场景描述:一个公司有3个部门,人事部、财务部和技术部,每个部门有一个负责人,员工请假需要先向其所在部门的负责人提交请假申请,如果负责人无法批准,则需要上级领导处理。

// 申请表
class LeaveRequest {
    private String name; // 姓名
    private int days; // 请假天数

    public LeaveRequest(String name, int days) {
        this.name = name;
        this.days = days;
    }

    public String getName() {
        return name;
    }

    public int getDays() {
        return days;
    }
}

// 抽象处理者
interface Handler {
    // 处理请求
    boolean handleRequest(LeaveRequest leaveRequest);

    // 设置下一个处理者
    void setNextHandler(Handler handler);
}

// 具体处理者-人事部负责人
class PersonnelHandler implements Handler {
    private Handler nextHandler;

    @Override
    public boolean handleRequest(LeaveRequest leaveRequest) {
        if (leaveRequest.getDays() <= 3) {
            System.out.println("人事部负责人批准" + leaveRequest.getName() + "的请假申请,天数为" + leaveRequest.getDays() + "天");
            return true;
        } else {
            if (nextHandler != null) {
                return nextHandler.handleRequest(leaveRequest);
            } else {
                return false;
            }
        }
    }

    @Override
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }
}

// 具体处理者-财务部负责人
class FinanceHandler implements Handler {
    private Handler nextHandler;

    @Override
    public boolean handleRequest(LeaveRequest leaveRequest) {
        if (leaveRequest.getDays() <= 5) {
            System.out.println("财务部负责人批准" + leaveRequest.getName() + "的请假申请,天数为" + leaveRequest.getDays() + "天");
            return true;
        } else {
            if (nextHandler != null) {
                return nextHandler.handleRequest(leaveRequest);
            } else {
                return false;
            }
        }
    }

    @Override
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }
}

// 具体处理者-技术部负责人
class TechnicalHandler implements Handler {
    private Handler nextHandler;

    @Override
    public boolean handleRequest(LeaveRequest leaveRequest) {
        if (leaveRequest.getDays() <= 7) {
            System.out.println("技术部负责人批准" + leaveRequest.getName() + "的请假申请,天数为" + leaveRequest.getDays() + "天");
            return true;
        } else {
            if (nextHandler != null) {
                return nextHandler.handleRequest(leaveRequest);
            } else {
                return false;
            }
        }
    }

    @Override
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }
}

// 责任链客户端
public class Client {

    public static void main(String[] args) {
        Handler personnelHandler = new PersonnelHandler();
        Handler financeHandler = new FinanceHandler();
        Handler technicalHandler = new TechnicalHandler();

        personnelHandler.setNextHandler(financeHandler);
        financeHandler.setNextHandler(technicalHandler);

        LeaveRequest request1 = new LeaveRequest("小明", 2);
        LeaveRequest request2 = new LeaveRequest("小红", 4);
        LeaveRequest request3 = new LeaveRequest("小刚", 6);
        LeaveRequest request4 = new LeaveRequest("小何", 10);

        personnelHandler.handleRequest(request1);
        personnelHandler.handleRequest(request2);
        personnelHandler.handleRequest(request3);
        personnelHandler.handleRequest(request4);
    }
}

运行结果:

人事部负责人批准小明的请假申请,天数为2天
财务部负责人批准小红的请假申请,天数为4天
技术部负责人批准小刚的请假申请,天数为6天

示例二

场景描述:一个人喜欢看动作电影和喜剧电影,他有两个电影分类的账号,为了避免每次登录都要进行选择分类,他希望选择一个账号后能自动显示和该账号对应的电影分类列表。

// 抽象处理者
public abstract class Handler {
    private Handler nextHandler;
    protected String account;

    public Handler(String account) {
        this.account = account;
    }

    // 处理请求
    public void handleRequest(String account) {
        if (account.equals(this.account)) {
            this.display();
        } else {
            if (nextHandler != null) {
                nextHandler.handleRequest(account);
            } else {
                System.out.println("没有找到该账号的电影分类列表");
            }
        }
    }

    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }

    public abstract void display();
}

// 具体处理者-动作电影分类列表
public class ActionHandler extends Handler {
    public ActionHandler(String account) {
        super(account);
    }

    @Override
    public void display() {
        System.out.println(this.account + ": 动作电影分类列表");
    }
}

// 具体处理者-喜剧电影分类列表
public class ComedyHandler extends Handler {
    public ComedyHandler(String account) {
        super(account);
    }

    @Override
    public void display() {
        System.out.println(this.account + ": 喜剧电影分类列表");
    }
}

// 责任链客户端
public class Client {

    public static void main(String[] args) {
        Handler actionHandler1 = new ActionHandler("账户1");
        Handler comedyHandler1 = new ComedyHandler("账户1");
        Handler actionHandler2 = new ActionHandler("账户2");
        Handler comedyHandler2 = new ComedyHandler("账户2");

        actionHandler1.setNextHandler(comedyHandler1);
        comedyHandler1.setNextHandler(actionHandler2);
        actionHandler2.setNextHandler(comedyHandler2);

        actionHandler1.handleRequest("账户1");
        actionHandler1.handleRequest("账户2");
        actionHandler1.handleRequest("账户3");
    }
}

运行结果:

账户1: 动作电影分类列表
账户2: 喜剧电影分类列表
没有找到该账号的电影分类列表

四、总结

责任链模式可以有效地解决请求发送者和接收者之间的耦合关系,使得多个对象都有机会处理同一个请求。在实际应用中,我们可以根据具体需求将责任链设置为不同的长度和顺序,以及不同的处理方式。同时,要注意控制责任链的长度和避免循环调用和死循环的出现,从而保证程序的正常运行和可维护性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Java实现设计模式之责任链模式 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • 使用Ajax更新ASP.Net MVC项目中的报表对象方法

    使用Ajax更新ASP.Net MVC项目中的报表对象方法,主要需要完成如下步骤: 在项目中安装必要的NuGet包,比如Microsoft.AspNet.Mvc、Microsoft.AspNet.WebPages。 在前端页面中引入jQuery库(比如使用CDN方式),并建立前端代码和后端代码之间的交互逻辑。 创建Controller和Action方法,用于…

    other 2023年6月27日
    00
  • 关于vba代码运行时错误1004 应用程序定义或对象定义错误问题

    当我们在使用VBA编写代码自动化Excel时,有时会遇到运行时错误1004,这个错误提示一般会说“应用程序定义或对象定义错误”,但直接通过这个提示很难找出具体的问题所在。下面我将为您介绍如何解决这个问题的完整攻略: 确认代码的正确性 有时候运行时错误1004是由代码本身的错误引起的。我们需要确认以下几点: 是否有语法错误,例如缺少括号或引号等 是否正确引用了…

    other 2023年6月25日
    00
  • Vue递归组件+Vuex开发树形组件Tree–递归组件的简单实现

    下面是关于”Vue递归组件+Vuex开发树形组件Tree–递归组件的简单实现”的完整攻略。 概述 在Vue开发过程中,经常会遇到需要处理树形结构的情况,此时使用递归组件就是最好的解决方案。本攻略将介绍如何使用Vue递归组件和Vuex开发树形组件。 实现步骤 步骤一:定义数据结构 首先我们需要定义树形数据结构,这里我们使用一个数组来表示一个节点,每个节点包含…

    other 2023年6月27日
    00
  • c#netty框架

    C# Netty框架 Netty是一个高性能、异步事件驱动的网络应用程序框架,支持多种协议和传输方式。C# Netty是Netty框架的C#版本,提供了类似于Java版本的API和功能。本文将介绍C# Netty框架的基本用法和常用组件。 安装C# Netty框架 您可以从C# Netty的官方网站下载最新版本的C# Netty框架。下载完成后,您需要将C#…

    other 2023年5月7日
    00
  • android使用AIDL跨进程通信(IPC)

    Android使用AIDL跨进程通信(IPC)攻略 AIDL(Android Interface Definition Language)是一种用于在Android应用程序之间进行跨进程通信(IPC)的机制。以下是使用AIDL进行跨进程通信的详细步骤: 定义AIDL接口 首先,需要定义一个AIDL接口,该接口定义了跨进程通信的方法。创建一个名为IMyServ…

    other 2023年10月13日
    00
  • oppoa11x如何打开开发者选项?

    以下是关于oppoa11x如何打开开发者选项的完整攻略: 第一步:打开系统设置 首先进入你的oppoa11x手机系统设置,可以在应用列表找到“设置”应用,点击打开。 第二步:找到“关于手机” 在系统设置界面中,向下滑动直到找到“系统和设备”选项。点击进入后,在列表中选择“关于手机”。 第三步:点击“版本号”七次 在“关于手机”页面中,找到“版本号”选项,注意…

    other 2023年6月26日
    00
  • XMind思维导图怎么设置主题优先级?

    XMind思维导图设置主题优先级攻略 1. 确定主题优先级的重要性 在进行主题优先级设置之前,首先需要明确主题优先级对你的思维导图的重要性。不同的主题可能具有不同的重要性,因此根据你的需求和目标来决定主题优先级的设置。 2. 使用主题优先级符号 使用XMind思维导图软件提供的主题优先级符号来设置主题的优先级。主题优先级符号可以使用不同的图标或颜色来表示主题…

    other 2023年6月28日
    00
  • js实现轮播图的两种方式(构造函数、面向对象)

    下面是详细讲解js实现轮播图的两种方式的完整攻略。 构造函数实现轮播图 步骤1:HTML结构 首先需要有一个HTML结构,用于放置轮播图的图片及导航按钮,示例如下: <div class="slider"> <ul> <li><img src="img1.jpg">&lt…

    other 2023年6月26日
    00
合作推广
合作推广
分享本页
返回顶部