狐言不胡言

导航

击鼓传花联想到了Java设计模式:责任链模式

应用场景

http web请求处理,请求过来后将经过转码、解析、参数封装、鉴权等一系列的处理(责任),而且要经过多少处理是可以灵活调整的
那么该怎么做呢?
将所有的处理都写在一个类中行不行呢?
分成多个类又该如何灵活的组合在一起呢?

简单示例

Request类:

public interface Request {
    //do something...
}

ResponsibilityChain类:

public class ResponsibilityChain {

    private List<Responsibility> responsibilityList = new ArrayList<>();

    private Integer index = 0;
    
    public void process(Request request) {
        if (this.index < responsibilityList.size()) {
            this.responsibilityList.get(index++).process(request, this);
        }
    }

    /** 加入链中 */
    public void register(Responsibility responsibility) {
        this.responsibilityList.add(responsibility);
    }
}

Responsibility接口:

public interface Responsibility {
    void process(Request request, ResponsibilityChain chain);
}

Responsibility实现类:

public class ResponsibilityA implements Responsibility {
    @Override
    public void process(Request request, ResponsibilityChain chain) {
        System.out.println("转码");
        chain.process(request);
    }
}
public class ResponsibilityB implements Responsibility {
    @Override
    public void process(Request request, ResponsibilityChain chain) {
        System.out.println("解析");
        chain.process(request);
    }
}
public class ResponsibilityC implements Responsibility {
    @Override
    public void process(Request request, ResponsibilityChain chain) {
        System.out.println("参数封装");
        chain.process(request);
    }
}
public class ResponsibilityD implements Responsibility {
    @Override
    public void process(Request request, ResponsibilityChain chain) {
        System.out.println("鉴权");
        chain.process(request);
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        ResponsibilityChain chain = new ResponsibilityChain();
        chain.register(new ResponsibilityA());
        chain.register(new ResponsibilityB());
        chain.register(new ResponsibilityC());
        chain.register(new ResponsibilityD());
        chain.process(new Request() {
        });
    }
}

在这里插入图片描述
类图:
在这里插入图片描述

责任链模式

定义

所有的处理者,都加入到这个链式,一个处理完后,转给下一个
或者说每个接收者都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者

  1. 抽象出责任接口,具体责任逻辑实现接口
  2. 根据处理过程需要,将具体实现组合成链
  3. 使用者使用链

典型的代表:Filter、Interceptor

意图

避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止

主要解决问题

职责链上的处理者负责处理请求,客户端只需要将请求发送到职责链上就行了,不需要关系处理的细节和请求的传递,请求的发送者和处理者解耦了

何时使用

  1. 系统已经有一个由处理者对象组成的链,这个链可能有合成模式给出
  2. 有多于一个的处理者对象会处理一个请求,而且事先并不清楚到底由哪一个处理者对象处理一个请求,处理者对象是动态确定的
  3. 系统想发出一个请求给多个处理者对象中的某一个,但是不明显指定哪一个处理者对象会处理该请求
  4. 处理一个请求的处理者对象集合需要动态的指定时

优缺点

优点:

  1. 发送者和接收者解耦,低耦合
  2. 简化了对象。使得对象不需要知道链的结构
  3. 通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任
  4. 增加新的请求处理类很方便

缺点:

  1. 不能保证请求一定被接收
  2. 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用
  3. 可能不容易观察运行时的特征,有碍于除错

类图如下:
在这里插入图片描述
涉及到的角色:

  1. 抽象处理者(Handler)角色:定义一个处理请求的接口,如果需要,接口可以定义出一个方法,以设定和返回对下家的引用,这个角色通常由一个抽象类或者接口实现
  2. 具体处理者(ConcreteHandler)角色:具体处理者接收到请求后,可以选择将请求处理掉,或者传给下一个;具体处理者持有对下一个的引用,因此如果需要,具体处理者可以访问下一个

代码示例:
Handler类:

public abstract class Handler {

    protected Handler successor;

    /** 调用此方法处理请求 */
    public abstract void handlerRequest();

    /** 取值方法 */
    public Handler getSuccessor() {
        return successor;
    }

    /** 调用此方法设置下一个 */
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
}

ConcreteHandler类:

public class ConcreteHandler1 extends Handler {
    @Override
    public void handlerRequest() {
        if (getSuccessor() != null) {
            System.out.println("请求传递到下一个:" + getSuccessor().getClass().getName());
            getSuccessor().handlerRequest();
        } else {
            System.out.println("请求在ConcreteHandler1被处理了");
        }
    }
}
public class ConcreteHandler2 extends Handler {
    @Override
    public void handlerRequest() {
        if (getSuccessor() != null) {
            System.out.println("请求传递到下一个:" + getSuccessor());
            getSuccessor().handlerRequest();
        } else {
            System.out.println("请求在ConcreteHandler2被处理了");
        }
    }
}

客户端:

public class Client {

    static private Handler handler1;

    static private Handler handler2;

    public static void main(String[] args) {
        handler1 = new ConcreteHandler1();
        handler2 = new ConcreteHandler2();
        handler1.setSuccessor(handler2);
        handler1.handlerRequest();
    }
}

类图:
在这里插入图片描述

击鼓传花的故事

击鼓传花是一种热闹而又紧张的饮酒游戏,在酒宴上宾客依次坐定,由一人击鼓,开始击鼓时,花束就开始依次传递,鼓声一落,如果花束在谁手里,谁就开始饮酒了;下面以《红楼梦》中击鼓传花的故事,写一个小例子:
在这里插入图片描述
抽象接口Player类:

public abstract class Player {

    private Player player;

    /** 需要执行酒令的请求 */
    abstract public  void handlerRequest(int index);

    /** 设置下一个传花人 */
    public void setPlayer(Player player) {
        this.player = player;
    }

    /** 将花传给下一家,如果没有就结束 */
    public void next(int index) {
        if (player != null) {
            player.handlerRequest(index);
        } else {
            System.out.println("传花结束");
        }
    }
}

参与击鼓传花的人:

public class JiaMu extends Player {

    public JiaMu(Player player) {
        this.setPlayer(player);
    }

    @Override
    public void handlerRequest(int index) {
        if (index == 1) {
            System.out.println("贾母执行酒令");
        } else {
            System.out.println("贾母将花传给下一个");
            next(index);
        }
    }
}
public class JiaShe extends Player {

    public JiaShe(Player player) {
        this.setPlayer(player);
    }

    @Override
    public void handlerRequest(int index) {
        if (index == 2) {
            System.out.println("贾赦执行酒令");
        } else {
            System.out.println("贾赦将花传给下一个");
            next(index);
        }
    }
}
public class JiaZheng extends Player {

    public JiaZheng(Player player) {
        this.setPlayer(player);
    }

    @Override
    public void handlerRequest(int index) {
        if (index == 3) {
            System.out.println("贾政执行酒令");
        } else {
            System.out.println("贾政将花传给下一个");
            next(index);
        }
    }
}
public class JiaBaoYu extends Player {

    public JiaBaoYu(Player player) {
        this.setPlayer(player);
    }

    @Override
    public void handlerRequest(int index) {
        if (index == 4) {
            System.out.println("贾宝玉执行酒令");
        } else {
            System.out.println("贾宝玉将花传给下一个");
            next(index);
        }
    }
}
public class JiaHuan extends Player {

    public JiaHuan(Player player) {
        this.setPlayer(player);
    }

    @Override
    public void handlerRequest(int index) {
        if (index == 5) {
            System.out.println("贾环执行酒令");
        } else {
            System.out.println("贾环将花传给下一个");
            next(index);
        }
    }
}

击鼓者:

public class DrinkingGame {

    static private Player player;

    public static void main(String[] args) {
        player = new JiaMu(
                  new JiaShe(
                  new JiaZheng(
                  new JiaBaoYu(
                  new JiaHuan(null)))));
        //设置第四个执行酒令
        player.handlerRequest(4);
    }
}

在这里插入图片描述
类图:
在这里插入图片描述

posted on 2021-04-17 10:36  狐言不胡言  阅读(161)  评论(0编辑  收藏  举报