zoukankan      html  css  js  c++  java
  • 设计模式(二)之责任链模式

    时空链接:

    1. 设计模式(一)之策略模式
    2. 设计模式(二)之责任链模式
    3. 设计模式(三)之模板模式
    4. 设计模式(四)之装饰者模式
    5. 设计模式(五)之适配器模式
    • 所有关于设计模式的代码,都会托管到:设计模式代码,欢迎关注。

    责任链模式

    概念

    责任链模式(Chain of Responsibility Pattern)为请求创建了一个接受这对象的链。这种模式基于请求的类型,对请求的发送者和接受者进行解耦。这种类型的设计模式同策略模式一样都属于行为型模式。何为解耦呢?就是说当客户端发出了一个请求,链上的对象都有机会来处理这一请求,而客户端不需要知道谁是具体的处理对象。

    特点

    • 更形象的描述为C语言的双向指针,每个处理器都明确的知道上一个处理器和下一个处理器是谁。
    • 多个对象可以处理同一个请求,但具体由哪个对象处理则是由运行时的环境决定。
    • 一个处理器对任务进行处理,可以添加一些操作后将对象传递给下一个任务。也可以在此对象上结束任务的处理,并结束任务。
    • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
    • 更好的体现了设计模式六大原则中的开闭原则。

    使用场景

    • Java过滤器的底层实现Filter。
    • 在网关中实现请求过滤,比如黑名单拦截、动态路由加载、动态鉴权判断等。

    优缺点

    • 优点:
    1. 降低了耦合度。它将请求的发送者和接收者解耦。
    2. 简化了对象。使得对象不需要知道链的结构。
    3. 增强给对象指派职责的灵活性。通过改变链内的成员后者调动它们的次序,允许动态的新增或者删除责任(满足"开-闭"原则)。
    4. 增加新的请求处理类很方便。
    • 缺点:
    1. 不能保证请求一定被接收。因此要定义默认的处理器进行额外处理没有经过链中的责任处理器处理过的请求(需提供默认责任处理)。
    2. 系统性能将受到一定影响,而且在进行代码调试时不是很方便,可能会造成循环调用。
    3. 可能不同意观察运行时的特征,有碍于除错。
    4. 如上所说,系统性能可能会有影响,因为功能处理都分散到了单独的职责对象中,每个对象功能单一,要把整个流程处理完,需要很多的职责对象,会产生大量的细粒度职责对象。

    模式的结构

    1. 抽象处理者(Handler)角色:定义一个处理请求的接口,包含处理方法和一个后继连接。
    2. 具体处理者(Concreate Handler)角色:实现抽象者的处理方法,判断能够处理本次请求,如果可以处理请求则处理,否则将请求转给它的后继者。
    3. 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它并不关心处理细节和请求的传递过程。

    图解如下:(来自网络图,后续编写的代码围绕该图编写)

    开发步骤

    • 建立数据库(design_pattern),和数据表(chain_of_responsibility)。表结构如下:
    CREATE TABLE `chain_of_responsibility` (
      `id` varchar(32) NOT NULL COMMENT '主键',
      `kind_handler` varchar(32) DEFAULT NULL COMMENT '处理器种类',
      `handler_id` varchar(32) DEFAULT NULL COMMENT '处理器id',
      `handler_name` varchar(32) DEFAULT NULL COMMENT '处理器名称',
      `pre_handler_id` varchar(32) DEFAULT NULL COMMENT '上一个处理器id',
      `next_handler_id` varchar(32) DEFAULT NULL COMMENT '下一个处理器id',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='责任链模式表';
    
    • 插入测试数据(实际应开发后台管理,可以动态的新增和修改来管控这些责任处理器)。
    INSERT INTO chain_of_responsibility VALUES ('aa928c3f312444b3a319dcf17b701bea', 'log','consoleLoggerHandler','标准日志输出', null, 'errorLoggerHandler');
    INSERT INTO chain_of_responsibility VALUES ('49f06f1e45ee4a79bb5a256909241bb3',  'log','errorLoggerHandler','ERROR日志输出', 'consoleLoggerHandler', 'debugLoggerHandler');
    INSERT INTO chain_of_responsibility VALUES ('685952c9cab647c2abad83ae1491dd7c', 'log' ,'debugLoggerHandler', 'debugger日志输出','errorLoggerHandler', null);
    
    • 引入maven环境依赖(项目工程见顶部,此处新增mysql相关依赖)
     <!-- mybatis启动器 -->
        <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <version>1.1.1</version>
        </dependency>
        <!-- 数据库依赖 -->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
        </dependency>
    
    • application.yml配置
    server:
      port: 8088
    
    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/design_pattern?useUnicode=true&characterEncoding=UTF-8
        username: root
        password: 123456
        driver-class-name: com.mysql.jdbc.Driver
    
    logging:
      level:
        # 打印Mybatis日志级别
        com.lee.chain.mapper: DEBUG
    
    mybatis:
      #实体扫描,多个package用逗号或者分号分隔
      mapper-locations: classpath:mapper/*.xml
    
    • 创建数据库表对应实体
    package com.lee.chain.entity;
    
    import java.io.Serializable;
    
    /**
     * @author zfl_a
     * @date 2020/8/11
     * @project springboot_design_pattern
     */
    public class ChainOfResponsibility implements Serializable {
    
        /**
         * 主键
         */
        private String id ;
    
        /**
         * 处理器中类
         */
        private String kindHandler ;
    
        /**
         * 处理器id
         */
        private String handlerId ;
    
        /**
         * 处理器名称
         */
        private String handlerName ;
    
        /**
         * 上一个处理器id
         */
        private String preHandlerId ;
    
        /**
         * 下一个处理器id
         */
        private String nextHandlerId ;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getKindHandler() {
            return kindHandler;
        }
    
        public void setKindHandler(String kindHandler) {
            this.kindHandler = kindHandler;
        }
    
        public String getHandlerId() {
            return handlerId;
        }
    
        public void setHandlerId(String handlerId) {
            this.handlerId = handlerId;
        }
    
        public String getHandlerName() {
            return handlerName;
        }
    
        public void setHandlerName(String handlerName) {
            this.handlerName = handlerName;
        }
    
        public String getPreHandlerId() {
            return preHandlerId;
        }
    
        public void setPreHandlerId(String preHandlerId) {
            this.preHandlerId = preHandlerId;
        }
    
        public String getNextHandlerId() {
            return nextHandlerId;
        }
    
        public void setNextHandlerId(String nextHandlerId) {
            this.nextHandlerId = nextHandlerId;
        }
    }
    
    
    • mapper接口
    package com.lee.chain.mapper;
    
    import com.lee.chain.entity.ChainOfResponsibility;
    
    /**
     * @author zfl_a
     * @date 2020/8/11
     * @project springboot_design_pattern
     */
    public interface ChainOfResponsibilityMapper {
    
        /**
         * 查询此种类中的第一个handler
         * @param kindHandler
         * @return
         */
        ChainOfResponsibility findTopChain(String kindHandler);
    
        /**
         * 查询当前的handler
         * @param handler
         * @return
         */
        ChainOfResponsibility findCurrentHandler(String handler);
    }
    
    
    • mapper.xml文件
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.lee.chain.mapper.ChainOfResponsibilityMapper">
    
        <select id="findTopChain" parameterType="string"
                resultType="com.lee.chain.entity.ChainOfResponsibility">
            select id , kind_handler as kindHandler,handler_id as handlerId,
                handler_name as handlerName , pre_handler_id as preHandlerId,
                next_handler_id as nextHandlerId from chain_of_responsibility
                where 1=1 and kind_handler=#{kindHandler} and pre_handler_id is null
        </select>
    
        <select id="findCurrentHandler" parameterType="string"
                resultType="com.lee.chain.entity.ChainOfResponsibility">
          select id , kind_handler as kindHandler,handler_id as handlerId,
                handler_name as handlerName , pre_handler_id as preHandlerId,
                next_handler_id as nextHandlerId from chain_of_responsibility
                where 1=1 and handler_id=#{handlerId}
        </select>
    
    </mapper>
    
    • 定义一个抽象类
    package com.lee.chain.service;
    
    /**
     * @author zfl_a
     * @Desc 根据级别来记录不同操作日志的handler
     * @date 2020/8/11
     * @project springboot_design_pattern
     */
    public abstract class AbstractLoggerHandler {
    
        protected int level ;
    
        protected AbstractLoggerHandler abstractLoggerHandler;
    
        public void setAbstractLoggerHandler(AbstractLoggerHandler abstractLoggerHandler){
            this.abstractLoggerHandler = abstractLoggerHandler ;
        }
        
        public void logMessage(int level,String message) {
            if(this.level<=level) {
                saveLogMessage(message);
            } else if(abstractLoggerHandler != null && this.level>level && abstractLoggerHandler.abstractLoggerHandler!=null) {
                System.out.println("无log处理器处理,请自定义默认处理器处理");
                return ;
            }
            //如果还有下一个处理器,继续调用,在各个处理器中,需要注意不存在的级别情况s
            if(abstractLoggerHandler!=null) {
                abstractLoggerHandler.logMessage(level,message);
            }
        }
    
        protected abstract void saveLogMessage(String message);
    
    }
    
    
    • 创建扩展类
    package com.lee.chain.service.impl;
    
    import com.lee.chain.service.AbstractLoggerHandler;
    import org.springframework.stereotype.Component;
    
    /**
     * @author zfl_a
     * @date 2020/8/11
     * @project springboot_design_pattern
     */
    @Component
    public class ConsoleLoggerHandler extends AbstractLoggerHandler {
    
        public ConsoleLoggerHandler(){
            this.level = 1 ;
        }
    
        @Override
        protected void saveLogMessage(String message) {
            System.out.println("Console: 标准日志输出...."+message);
    
            return ;
        }
    }
    
    
    package com.lee.chain.service.impl;
    
    import com.lee.chain.service.AbstractLoggerHandler;
    import org.springframework.stereotype.Component;
    
    /**
     * @author zfl_a
     * @date 2020/8/11
     * @project springboot_design_pattern
     */
    @Component
    public class DebugLoggerHandler extends AbstractLoggerHandler {
    
        public DebugLoggerHandler(){
            this.level = 3 ;
        }
    
        @Override
        protected void saveLogMessage(String message) {
    
            System.out.println("Debugger: 开发环境日志输出...."+message);
            return ;
        }
    }
    
    
    package com.lee.chain.service.impl;
    
    import com.lee.chain.service.AbstractLoggerHandler;
    import org.springframework.stereotype.Component;
    
    import java.util.UUID;
    
    /**
     * @author zfl_a
     * @date 2020/8/11
     * @project springboot_design_pattern
     */
    @Component
    public class ErrorLoggerHandler extends AbstractLoggerHandler {
    
       public ErrorLoggerHandler(){
           this.level = 2 ;
       }
    
        @Override
        protected void saveLogMessage(String message) {
            System.out.println("Error: 错误日志输出...." + message);
            return ;
        }
    }
    
    • 创建客户类
    package com.lee.chain.service;
    
    /**
     * @author zfl_a
     * @date 2020/8/11
     * @project springboot_design_pattern
     */
    public interface ChainOfResponsibilityService {
    
        /**
         * 查找指定种类的顶级处理器
         * @param kindHandler
         * @return
         */
        AbstractLoggerHandler findTopLogHandler(String kindHandler);
    }
    
    
    package com.lee.chain.service.impl;
    
    import com.lee.chain.entity.ChainOfResponsibility;
    import com.lee.chain.mapper.ChainOfResponsibilityMapper;
    import com.lee.chain.service.AbstractLoggerHandler;
    import com.lee.chain.service.ChainOfResponsibilityService;
    import com.lee.utils.SpringUtils;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * @author zfl_a
     * @date 2020/8/11
     * @project springboot_design_pattern
     */
    @Service
    public class ChainOfResponsibilityServiceImpl implements ChainOfResponsibilityService {
    
        @Autowired
        private ChainOfResponsibilityMapper chainOfResponsibilityMapper ;
    
        private AbstractLoggerHandler abstractLoggerHandler ;
    
        @Override
        public AbstractLoggerHandler findTopLogHandler(String kindHandler) {
    
            if (this.abstractLoggerHandler != null) {
                return this.abstractLoggerHandler;
            }
            // 查询此种类中的第一个handler
            ChainOfResponsibility responsibility = chainOfResponsibilityMapper.findTopChain(kindHandler);
            if (responsibility == null) {
                return null;
            }
            String topHandlerId = responsibility.getHandlerId();
            if (StringUtils.isEmpty(topHandlerId)) {
                return null;
            }
            // 从容器中获取bean
            AbstractLoggerHandler topLogBeanHandler = SpringUtils.getBean(topHandlerId, AbstractLoggerHandler.class);
            if (topLogBeanHandler == null) {
                return null;
            }
            // 获取下一个handlerID
            String nextHandlerId = responsibility.getNextHandlerId();
            // 定定义一个临时变量存放
            AbstractLoggerHandler tempTopLogBeanHandler = topLogBeanHandler;
            while (!StringUtils.isEmpty(nextHandlerId)) {
                // 从容器中获取该nextHandlerId对应的对象
                AbstractLoggerHandler nextLogHandler = SpringUtils.getBean(nextHandlerId, AbstractLoggerHandler.class);
                if (nextLogHandler == null) {
                    break;
                }
                // 查询当前handler信息
                ChainOfResponsibility nextLogHandlerResponsibility = chainOfResponsibilityMapper.findCurrentHandler(nextHandlerId);
                if (nextLogHandlerResponsibility == null) {
                    break;
                }
                // 当下一个handler为空时退出循环
                nextHandlerId = nextLogHandlerResponsibility.getNextHandlerId();
                tempTopLogBeanHandler.setAbstractLoggerHandler(nextLogHandler);
                tempTopLogBeanHandler = nextLogHandler;
            }
            this.abstractLoggerHandler = topLogBeanHandler;
            return abstractLoggerHandler;
    
        }
    }
    
    
    • 创建测试控制器
    package com.lee.chain.controller;
    
    import com.lee.chain.service.AbstractLoggerHandler;
    import com.lee.chain.service.ChainOfResponsibilityService;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author zfl_a
     * @date 2020/8/11
     * @project springboot_design_pattern
     */
    @RestController
    @RequestMapping("/chain")
    public class ChainOfResponsibilityController {
    
        @Autowired
        private ChainOfResponsibilityService chainOfResponsibilityService ;
    
        /**
         *
         * @param level 日志级别 级别 1INFO 2ERRPR 3DEBUGGER
         * @param kindHandler 种类 目前只有一种 log
         * @param message 消息
         * @return
         */
        @GetMapping("/logMessage")
        public Map<String,Object> logMessage(String level,String kindHandler,String message) {
    
    
    
            Map<String,Object> results = new HashMap<>();
            results.put("code","200");
            results.put("msg","操作成功");
    
            if(StringUtils.isBlank(level)) {
                results.put("code","-2");
                results.put("msg","请传递级别 1INFO 2ERRPR 3DEBUGGER");
            }
    
            AbstractLoggerHandler topLogHandler = chainOfResponsibilityService.findTopLogHandler(kindHandler);
            if(topLogHandler!=null) {
                topLogHandler.logMessage(Integer.parseInt(level),message);
            }
            return results ;
        }
    }
    
    
    • 测试结果如下:
    1. 当参数为level=1&kindHandler=log&message=chainOfResponsibility,打印结果如下:
    2. 当参数为level=3&kindHandler=log&message=chainOfResponsibility,打印结果如下:
    3. 当参数为level=-1&kindHandler=log&message=chainOfResponsibility,打印结果如下:

    所有关于设计模式的代码,都会托管到:设计模式代码,欢迎关注。希望和大家一起共同成长!

    充满鲜花的世界到底在哪里
  • 相关阅读:
    数据对象映射模式
    策略模式
    适配模式
    注册模式
    单例模式
    工厂模式
    PHP魔法方法的使用
    【转】通过 ulimit 改善系统性能
    HDMI相关知识
    中国三种3G网络频段
  • 原文地址:https://www.cnblogs.com/aliases/p/13487985.html
Copyright © 2011-2022 走看看