责任链设计模式

责任链设计模式

原文: https://howtodoinjava.com/design-patterns/behavioral/chain-of-responsibility-design-pattern/

责任链被称为行为型模式。 这种模式的主要目的是避免将请求的发送方耦合到接收方,从而为多个对象提供了处理请求的机会。 GoF 定义的核心逻辑是:

"Gives more than one object an opportunity to handle a request by linking receiving objects together."

责任链允许许多类尝试处理请求,而与链上的任何其他对象无关。 处理完请求后,它就完成了整个流程。

可以在链中添加或删除额外的处理器,而无需修改任何具体处理器内部的逻辑。

Sections in this post:

Suggested usage
Participants in the solution
Sample problem to be solved
Proposed solution
Class diagram of participants
Sourcecode of participants
Test the application
Download sourecode link
Reference implementations in JDK

建议用法

当多个对象可以处理一个请求并且处理器不必是特定的对象时,建议使用此模式。 另外,处理器是在运行时确定的。 请注意,任何处理器都不处理的请求是有效的用例。

例如,Windows OS 中的事件处理机制,可以从鼠标,键盘或某些自动生成的事件生成事件。 所有这些事件都可以由多个处理器处理,并且在运行时可以找到正确的处理器。

更一般的例子可以是对呼叫中心的服务请求。 可以在前台,主管或任何更高级别处理此请求。 仅当在各个级别上遍历请求时,才在运行时知道正确的请求处理器。 我们将在这篇文章中解决这种情况。

解决方案中的参与者

1)Handler:这可以是一个主要接收请求并将请求分派到处理器链的接口。 它仅引用链中的第一个处理器,而对其余处理器一无所知。

2)ConcreteHandler:这些是按某些顺序链接的请求的实际处理器。

3)Client:请求的始发者,它将访问处理器来处理它。

Participants in chain of responsibility

责任链中的参与者

要解决的示例问题

问题陈述是为支持服务系统设计一个系统,该系统由前台,主管,经理和主管组成。 任何客户都可以致电前台,并寻求解决方案。 如果前台能够解决问题,它将解决; 否则将转交给主管。 同样,主管将尝试解决该问题,如果他能够解决,则将解决; 否则传给经理。 同样,经理将解决问题或转给董事。 导演将解决该问题或拒绝它。

建议的解决方案

以上问题是使用责任链模式的良好人选。 我们可以在每个级别上定义处理器,即支持台,主管,经理和主管。 然后,我们可以定义一条链来处理支持请求。 该链必须遵循以下顺序:

Support desk > supervisor > manager > director

上面的链也可以使用 Java 中的编程解决方案进行管理,但是在本教程中,我将使用 spring 注入依赖项,从而形成该链。 同样,系统将首先将请求仅分配给前台。

参与者的类图

我已经绘制了解决方案中涉及的所有实体的结构,如下所示。

Chain of responsibility class diagram

支持服务系统:类图

参与者的源代码

以下是使用责任链设计模式实现支持服务的所有参与者的源代码:

ServiceLevel.java

package com.howtodoinjava;

public enum ServiceLevel
{
	LEVEL_ONE, LEVEL_TWO, LEVEL_THREE, LEVEL_FOUR, INVALID_REQUEST
}

ServiceRequest.java

package com.howtodoinjava.data;

import com.howtodoinjava.ServiceLevel;

public class ServiceRequest {

	private ServiceLevel type;
	private String conclusion = null;

	public ServiceLevel getType() {
		return type;
	}
	public void setType(ServiceLevel type) {
		this.type = type;
	}
	public String getConclusion() {
		return conclusion;
	}
	public void setConclusion(String conclusion) {
		this.conclusion = conclusion;
	}
}

SupportServiceItf.java

package com.howtodoinjava.handler;

import com.howtodoinjava.data.ServiceRequest;

public interface SupportServiceItf
{
	public void handleRequest(ServiceRequest request);
}

SupportService.java

package com.howtodoinjava.handler;

import com.howtodoinjava.data.ServiceRequest;

public class SupportService implements SupportServiceItf {

	private SupportServiceItf handler = null;

	public SupportServiceItf getHandler() {
		return handler;
	}

	public void setHandler(SupportServiceItf handler) {
		this.handler = handler;
	}

	@Override
	public void handleRequest(ServiceRequest request) {
		handler.handleRequest(request);
	}
}

FrontDeskSupport.java

package com.howtodoinjava.handler;

import com.howtodoinjava.ServiceLevel;
import com.howtodoinjava.data.ServiceRequest;

public class FrontDeskSupport implements SupportServiceItf {

	private SupportServiceItf next = null;
	public SupportServiceItf getNext() {
		return next;
	}
	public void setNext(SupportServiceItf next) {
		this.next = next;
	}

	@Override
	public void handleRequest(ServiceRequest service) {
		if(service.getType() == ServiceLevel.LEVEL_ONE)
		{
			service.setConclusion("Front desk solved level one reuqest !!");
		}
		else
		{
			if(next != null){
				next.handleRequest(service);
			}
			else
			{
				throw new IllegalArgumentException("No handler found for :: " + service.getType());
			}
		}
	}
}

SupervisorSupport.java

package com.howtodoinjava.handler;

import com.howtodoinjava.ServiceLevel;
import com.howtodoinjava.data.ServiceRequest;

public class SupervisorSupport implements SupportServiceItf {

	private SupportServiceItf next = null;
	public SupportServiceItf getNext() {
		return next;
	}
	public void setNext(SupportServiceItf next) {
		this.next = next;
	}

	@Override
	public void handleRequest(ServiceRequest request) {
		if(request.getType() == ServiceLevel.LEVEL_TWO)
		{
			request.setConclusion("Supervisor solved level two reuqest !!");
		}
		else
		{
			if(next != null){
				next.handleRequest(request);
			}
			else
			{
				throw new IllegalArgumentException("No handler found for :: " + request.getType());
			}
		}
	}
}

ManagerSupport.java

package com.howtodoinjava.handler;

import com.howtodoinjava.ServiceLevel;
import com.howtodoinjava.data.ServiceRequest;

public class ManagerSupport implements SupportServiceItf {

	private SupportServiceItf next = null;
	public SupportServiceItf getNext() {
		return next;
	}
	public void setNext(SupportServiceItf next) {
		this.next = next;
	}

	@Override
	public void handleRequest(ServiceRequest request) {
		if(request.getType() == ServiceLevel.LEVEL_THREE)
		{
			request.setConclusion("Manager solved level three reuqest !!");
		}
		else
		{
			if(next != null){
				next.handleRequest(request);
			}
			else
			{
				throw new IllegalArgumentException("No handler found for :: " + request.getType());
			}
		}
	}
}

DirectorSupport.java

package com.howtodoinjava.handler;

import com.howtodoinjava.ServiceLevel;
import com.howtodoinjava.data.ServiceRequest;

public class DirectorSupport implements SupportServiceItf {

	private SupportServiceItf next = null;
	public SupportServiceItf getNext() {
		return next;
	}
	public void setNext(SupportServiceItf next) {
		this.next = next;
	}

	@Override
	public void handleRequest(ServiceRequest request) {
		if(request.getType() == ServiceLevel.LEVEL_FOUR)
		{
			request.setConclusion("Director solved level four reuqest !!");
		}
		else
		{
			if(next != null){
				next.handleRequest(request);
			}
			else
			{
				request.setConclusion("You problem is none of our business");
				throw new IllegalArgumentException("You problem is none of our business :: " + request.getType());
			}
		}
	}
}

applicationConfig.xml

<?xml  version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="supportService" class="com.howtodoinjava.handler.SupportService">
        <property name="handler" ref="frontDeskSupport"></property>
    </bean>

    <bean id="frontDeskSupport" class="com.howtodoinjava.handler.FrontDeskSupport">
        <property name="next" ref="supervisorSupport"></property>
    </bean>
    <bean id="supervisorSupport" class="com.howtodoinjava.handler.SupervisorSupport">
        <property name="next" ref="managerSupport"></property>
    </bean>
    <bean id="managerSupport" class="com.howtodoinjava.handler.ManagerSupport">
        <property name="next" ref="directorSupport"></property>
    </bean>
    <bean id="directorSupport" class="com.howtodoinjava.handler.DirectorSupport"></bean>

</beans>

测试应用

我将在链下传递各种级别的支持请求,这些请求将由正确的级别处理。 任何无效的请求将按计划被拒绝。

package com.howtodoinjava;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.howtodoinjava.data.ServiceRequest;
import com.howtodoinjava.handler.SupportService;

public class TestChainOfResponsibility {
	public static void main(String[] args)
	{
		ApplicationContext context = new ClassPathXmlApplicationContext("application-config.xml");
		SupportService supportService = (SupportService) context.getBean("supportService");

		ServiceRequest request = new ServiceRequest();
		request.setType(ServiceLevel.LEVEL_ONE);
		supportService.handleRequest(request);
		System.out.println(request.getConclusion());

		request = new ServiceRequest();
		request.setType(ServiceLevel.LEVEL_THREE);
		supportService.handleRequest(request);
		System.out.println(request.getConclusion());

		request = new ServiceRequest();
		request.setType(ServiceLevel.INVALID_REQUEST);
		supportService.handleRequest(request);
		System.out.println(request.getConclusion());
	}
}

<strong>Output:</strong>

Front desk solved level one reuqest !!
Manager solved level three reuqest !!
Exception in thread "main" java.lang.IllegalArgumentException: You problem is none of our business :: INVALID_REQUEST

要下载上述示例应用的源代码,请单击以下链接。

JDK 中的参考实现

每当客户端对链末端的资源提出请求时,每次通过链传递请求/响应对时,容器都会调用FilterdoFilter方法。 传入此方法的FilterChain允许Filter将请求和响应传递给链中的下一个实体。

如果当前为给定消息级别启用了记录器,则将给定消息转发到所有已注册的输出Handler对象。

我希望这篇文章能为您对责任链模式的理解增加一些知识。 如有任何疑问,请发表评论。

祝您学习愉快!