设计模式——责任链模式(Chain of Responsibility Pattern)

责任链模式是将链中的每一个节点看作是一个对象,每个节点处理的请求都不相同,且内部自动维护下一个节点对象。每个请求从链式首端发出,沿着链依次经过每个节点,如果当前节点无法处理自动传递给下一个节点,直到链上某个节点处理完请求,则链结束。属于行为型模式。

适用场景:

  • 多个对象可以处理同一请求,但具体哪个对象处理在运行时动态决定;
  • 在不明确接收者情况下,向多个对象提交一个请求;
  • 可动态指定一组对象处理请求;

责任链在框架中的应用:

JDK中Filter, Spring对FilterChain进行了实现,通过List将所有Filter封装起来

Netty中ChannelPipeline, pipeline由ChannelHandler组成,pipeline中有head和tail组成一个双向链,ChannelHandler分为InBoundHandler(数据输入进行解码)和OutBoundHandler(对数据进行编码输出)。

优点:

  • 将请求与处理解耦;
  • 请求处理者(链上的节点对象)只需要关注自己相关的请求进行处理,不相关的请求直接转给下一个节点对象;
  • 可以链式传递处理请求,请求发送者无须知道链路结构和细节,只需等待处理结果;
  • 链路结构灵活,可以通过改变链路结构动态新增或删除处理过程;
  • 易于扩展新的请求处理类,符合开闭原则;

缺点:

  • 如果责任链太长或处理时间过长,会影响整体性能;
  • 如果节点对象存在循环引用,有可能出现死循环,导致系统崩溃;

代码演示

下面写个简单的模拟用户登录的代码来演示下责任链模式的使用

使用责任链模式前代码

public class LoginService {
    public void login(String username, String pwd) {
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(pwd)) {
            System.out.println("用户名或密码为空!");
            return;
        }
        User user = checkExist(username, pwd);
        if (null == user) {
            System.out.println("用户不存在!");
            return;
        }
        System.out.println("登陆成功");
        if (!"admin".equals(user.getRole())) {
            System.out.println("您不是管理员,没有操作权限!");
            return;
        }
        System.out.println("操作成功");
    }

    private User checkExist(String username, String pwd) {
        Map userMap = new HashMap<>();
        userMap.put("Lucifer&&&admin", new User("Lucifer", "admin", "admin"));
        if (userMap.containsKey(username + "&&&" + pwd)) {
            return userMap.get(username + "&&&" + pwd);
        }
        return null;
    }
}
public class LoginTest {
    public static void main(String[] args) {
        LoginService service = new LoginService();
        service.login("Lucifer", "admin");
    }
}

使用责任链后代码

链上节点抽象类

public abstract class AbstractHandler {
    protected AbstractHandler nextHandler;
    protected void next(AbstractHandler handler) {
        this.nextHandler = handler;
    }
    public abstract void doHandler(User obj);

    public static class Builder {
        private AbstractHandler head;
        private AbstractHandler tail;
        public Builder addHandler(AbstractHandler handler) {
            if (this.head == null) {
                this.head = this.tail = handler;
                return this;
            }
            this.tail.next(handler);
            this.tail = handler;
            return this;
        }
        public AbstractHandler build() {
            return this.head;
        };
    }
}

链上的三个节点处理类 

public class ValidationHandler extends AbstractHandler {
    @Override
    public void doHandler(User user) {
        if (StringUtils.isEmpty(user.getUsername()) || StringUtils.isEmpty(user.getPwd())) {
            System.out.println("用户名或密码为空!");
            return;
        }
        this.nextHandler.doHandler(user);
    }
}
public class DBHandler extends AbstractHandler {
    @Override
    public void doHandler(User u) {
        User user = checkExist(u.getUsername(), u.getPwd());
        if (null == user) {
            System.out.println("用户不存在!");
            return;
        }
        System.out.println("登陆成功");
        this.nextHandler.doHandler(user);
    }

    private User checkExist(String username, String pwd) {
        Map userMap = new HashMap<>();
        userMap.put("Lucifer&&&admin", new User("Lucifer", "admin", "admin"));
        if (userMap.containsKey(username + "&&&" + pwd)) {
            return userMap.get(username + "&&&" + pwd);
        }
        return null;
    }
}
public class AuthHandler extends AbstractHandler {
    @Override
    public void doHandler(User user) {
        if (!"admin".equals(user.getRole())) {
            System.out.println("您不是管理员,没有操作权限!");
            return;
        }
        System.out.println("操作成功");
    }
}

 将所有节点的处理类串成一个链,并从链首执行

public class LoginService {
    public void login(String username, String pwd) {
        AbstractHandler.Builder builder = new AbstractHandler.Builder();
        builder.addHandler(new ValidationHandler()).addHandler(new DBHandler()).addHandler(new AuthHandler());
        User u = new User();
        u.setUsername(username);
        u.setPwd(pwd);
        builder.build().doHandler(u);
    }
}
public class LoginTest {
    public static void main(String[] args) {
        LoginService service = new LoginService();
        service.login("Lucifer", "admin");
    }
}

面试题

责任链模式的实现原理?

责任链模式有两种实现方式,单向链表,双向链表,通过上下文保存头和尾,每个handler中设置下一个节点,但是链不能太长,否则影响性能,还要避免节点之间互相引用出现死循环

你可能感兴趣的:(设计模式,责任链模式)