【进阶之路】理解行为型模式开发(责任链模式)

1,192 阅读5分钟

大家好,我是练习java两年半时间的南橘,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西。知识越分享越值钱,我这段时间总结(包括从别的大佬那边学习,引用)了一些平常学习和面试中的重点(自我认为),希望给大家带来一些帮助

有需要的同学可以加我的公众号,以后的最新的文章第一时间都在里面,也可以找我要思维导图

【进阶之路】理解结构型模式开发(桥接模式)

【进阶之路】理解结构型模式开发(享元模式)

【进阶之路】理解结构型模式开发(适配器模式)

之前和大家分享了设计模式中的结构型模式,它主要是描述如何将类或对象通过组合新来实现功能,而我也是挑选了结构型模式中一些新接触设计模式的同学们不太能注意到的与大家分享(像代理模式、装饰模式等都是平常学习中接触较多的)。分享的初衷也是自己在工作中灵光一现发现可以用这种模式来提高效率(特指桥接模式)。

那么这次,我准备和大家分享行为型模式中的责任链模式。

初衷也是我在完成需求的时候,碰巧研究了一下自己的代码,发现用到了过滤器模式和责任链模式(过滤器模式其实在标准的API文档里没有找到,但是网上也有介绍这个)。

一、定义

责任链模式的定义

为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

在责任链模式中,我们只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了

责任链模式的优点

  • 1、降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。

  • 2、增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。

  • 3、增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。

  • 4、责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。

  • 5、责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

责任链模式的缺点

  • 1、不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。(不过这一点可以用默认值来处理,在路由选择上就设计了默认值
  • 2、对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响()。
  • 3、职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用

职责链模式主要角色:

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

二、实现责任链模式

根据路由选择器的过滤器模式+责任链模式,我们这边首先实现过滤连,将过滤器组装进来。

我们代码实现一次简单的过滤,过滤条件大概是是否能获得北京某借贷公司发放给本地人的小额贷款。

1、过滤链

每个各司其职的Filter都有可能被执行,我们可以将其串成一条链


public class FilterChain {
    @Autowired
    private List<Filter> filters;

    public FilterChain() {
        filters =new ArrayList<>();
        System.out.println("过滤器链路初始化.....");
        filters.add(new AgeFilter());
        filters.add(new hukouFilter());
        filters.add(new IncomeFilter());
        System.out.println("过滤器链路加载完毕.....");
    }
    
	//轮询调用已加载的过滤器
    public void processData(UserInfo data) {
        for (Filter filter : filters) {
            boolean b = filter.doFilter(data);
            if (!b){
                break;
            }
        }
    }
}

2、抽象处理者角色

public interface Filter {
    // 过滤器处理
    boolean doFilter(UserInfo data);
}

3、具体处理者角色

public class AgeFilter implements Filter {

    public AgeFilter() {
        System.out.println("年龄过滤器加载");
    }

    @Override
    public boolean doFilter(UserInfo data) {
        System.out.println("年龄风控拦截......");
        if (data.getAge()<18){
            System.out.println(data.getName()+"年龄低于18岁");
            return false;
        }
        return true;
    }
}
public class hukouFilter implements Filter {
    public hukouFilter() {
        System.out.println("户口过滤器加载");
    }

    @Override
    public boolean doFilter(UserInfo data) {
        System.out.println("户口拦截判断......");
        if ("北京".equals(data.getHukou())){
            return true;
        }
        System.out.println(data.getName()+"不是北京户口,无法借款");
        return false;
    }
}
public class IncomeFilter implements Filter {
    public IncomeFilter() {
        System.out.println("收入过滤器加载");
    }
    @Override
    public boolean doFilter(UserInfo data) {
        System.out.println("收入风控拦截......");
        if (data.getIncome()<100000) {
            if ("北京".equals(data.getHukou())) {
                System.out.println(data.getName() + "年收入低于10w,但是是北京户口,给予通过");
                return true;
            }
            System.out.println(data.getName() + "年收入低于10w");
            return false;
        }
        return true;
    }
}

4、测试类(客户类)

public class UserInfo {
    private String name;
    private Integer age;
    private Integer income;
    private String hukou;

    public UserInfo(Integer age, Integer income, String hukou,String name) {
        this.age = age;
        this.income = income;
        this.hukou = hukou;
        this.name =name;
    }
  }
      public static void main(String[] args) {
        UserInfo personA =new UserInfo(32,200000,"湘西", "小林");
        UserInfo personB =new UserInfo(22,90000,"北京","小罗");
        FilterChain f =new FilterChain();
        f.processData(personA);
        f.processData(personB);
    }

我们在很多地方都能看到这样的责任链模式,那么我是你要这样干?如果想要便捷的话,不如直接增加一个if,一个处理方法来得方便。

没错,但是遇上代码量大,链路长,甚至有几十层过滤器的时候,责任链分工明确,解耦,容易维护的好处就体现出来了。

三、责任链模式的应用

1、应用场景

  • 1、一个请求需要请求多个处理的类,哪个对象处理该请求由运行时刻自动确定时,可以使用责任链模式进行处理。
  • 2、需要动态指定一组对象处理请求,同时经常添加新的处理者的时候。
  • 3、在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求的时候。

除了过滤器这里,在实际开发中,各种路由的选择也通常需要依靠责任链模式来实现,比如说网上比较火的小贷。许多银行都有提供贷款的业务,如果同时有多个贷款业务在运转中的话,用户申请贷款的时候系统会在后台走一遍资金路由的流程,最后选择用户最适合的产品给用户开通

当然,除了这样的设计,责任链模式还有一种玩法,就是分段处理模式。一个用户如果需要被处理的内容特别多,为了尽量不违反单一职责原则和接口隔离原则,可以将这些处理类也用责任链的方式串联起来,每一个处理类处理一部分的内容,等责任链走完后,自然也就处理完毕了。

当然,这样也可能遇到新的问题,比如处理到一半突然系统出错了之类的。需要这样处理的话,也可以充分的利用幂等性原则,将状态储存下来,等问题修复后从出错的地方再次处理。

结语

这段时间一口气写了很多文章,主要是把之前存的一些内容给用上了。因为前段时间很忙,自己又换了新的工作,所以没有太多时间写作。这段时间慢慢地适应新环境,也就爆发了一波,希望大家能够多多支持。