网站建设所用软件,网站上传程序流程,企业网站优化应该怎么做,2017网站开发兼职目录定义标准模式实现#xff1a;职责链变体使用链表实现使用数组实现应用场景日志输出spring过滤器spirng 拦截器mybatis动态sql定义
责链模式是一种设计模式#xff0c;其目的是使多个对象能够处理同一请求#xff0c;但是并不知道下一个处理请求的对象是谁。它能够解耦请…
目录定义标准模式实现职责链变体使用链表实现使用数组实现应用场景日志输出spring过滤器spirng 拦截器mybatis动态sql定义
责链模式是一种设计模式其目的是使多个对象能够处理同一请求但是并不知道下一个处理请求的对象是谁。它能够解耦请求的发送者和接收者之间的直接耦合关系。 举个例子假设你的公司有一个报销流程需要依次提交给主管、经理和财务部门审核如果一个人无法审核那么就需要向下一个人提交审核请求。在这种情况下职责链模式非常适用。 在职责链模式中每个处理请求的对象都可以尝试处理请求如果自己无法处理则将请求传递给下一个对象直到有一个对象能够处理请求为止。 职责链模式由以下几个部分组成
抽象处理者Handler定义一个处理请求的接口并将请求传递给下一个处理者。具体处理者ConcreteHandler实现处理请求的接口并负责处理请求或者将请求传递给下一个处理者。客户端Client创建处理者对象并将请求发送给处理者。
通过这种方式我们可以将处理请求的对象连接成一条链让每个对象都有机会处理请求同时又不会知道下一个对象是谁。 标准模式实现
如果处理器链上的某个处理器能够处理这个请求那就不会继续往下传递请求。
这段代码是一个使用职责链模式的示例主要包含以下几个类
抽象处理器类 Handler 定义了一个处理器对象的公共接口并且持有下一个处理器的引用。具体的处理器需要继承自该类并实现其 doHandle() 方法用于实现处理逻辑。具体处理器类 HandlerA 和 HandlerB 继承自 Handler 类实现了 doHandle() 方法并且在该方法中输出自己的类名。处理器链类 HandlerChain 用于维护处理器链实现了 addHandler() 方法用于添加处理器实现了 handle() 方法用于处理请求。测试类 HandlerTest 创建了一个处理器链并添加了两个处理器然后调用 handle() 方法处理请求。
具体的实现过程如下
在抽象处理器类 Handler 中定义了一个 handle() 方法其中先调用 doHandle() 方法来执行实际的处理逻辑如果返回值为 false则表示当前处理器不能处理该请求需要将请求传递给下一个处理器。这里使用了模板方法设计模式。在具体处理器类 HandlerA 和 HandlerB 中分别实现了 doHandle() 方法输出自己的类名并且将返回值设置为 false。在处理器链类 HandlerChain 中定义了一个头部处理器和尾部处理器以及 addHandler() 方法用于添加处理器。当添加第一个处理器时同时将头部和尾部处理器设置为该处理器当添加多个处理器时将新的处理器设置为尾部处理器的下一个处理器并将尾部处理器设置为新的处理器。在 handle() 方法中调用头部处理器的 handle() 方法从而开始处理请求。在测试类 HandlerTest 中创建了一个处理器链并添加了 HandlerA 和 HandlerB 处理器。然后调用 handle() 方法处理请求从而开始执行处理逻辑。在执行过程中处理器链会将请求传递给每个处理器直到找到能够处理该请求的处理器为止。在本例中由于处理器只输出自己的类名因此实际上并没有进行实际的处理逻辑。
public abstract class Handler {protected Handler successor null;public void setSuccessor(Handler successor) {this.successor successor;}/**
* 利用模版方法抽离公共的逻辑
*/public final void handle() {boolean handled doHandle();if (successor ! null !handled) {successor.handle();}}/**
* 此处子类实现填充需要处理的逻辑
* 如果处理器链上的某个处理器能够处理这个请求那就不会继续往下传递请求
*
* return
*/protected abstract boolean doHandle();
}public class HandlerA extends Handler {Overrideprotected boolean doHandle() {boolean handled false;System.out.println(我是 this.getClass().getSimpleName());return handled;}
}public class HandlerB extends Handler {Overrideprotected boolean doHandle() {boolean handled false;System.out.println(我是 this.getClass().getSimpleName());return handled;}
}public class HandlerChain {private Handler head null;private Handler tail null;public void addHandler(Handler handler) {//将传入的节点下一步设置为nullhandler.setSuccessor(null);if (head null) {head handler;tail handler;return;}//尾部增加节点tail.setSuccessor(handler);tail handler;}public void handle(){if (head ! null) {head.handle();}}
}public class HandlerTest {public static void main(String[] args) {HandlerChain chain new HandlerChain();chain.addHandler(new HandlerA());chain.addHandler(new HandlerB());chain.handle();}
}
职责链变体
请求会被所有的处理器都处理一遍不存在中途终止的情况。这种变体也有两种实现方式用链表存储处理器和用数组存储处理器
使用链表实现 public abstract class Handler {protected Handler successor null;public void setSuccessor(Handler successor) {this.successor successor;}public final void handle() {doHandle();if (successor ! null) {successor.handle();}}protected abstract void doHandle();
}public class HandlerA extends Handler {Overrideprotected void doHandle() {System.out.println(我是 this.getClass().getSimpleName());}
}public class HandlerB extends Handler {Overrideprotected void doHandle() {System.out.println(我是 this.getClass().getSimpleName());}
}public class HandlerChain {private Handler head null;private Handler tail null;public void addHandler(Handler handler) {handler.setSuccessor(null);if (head null) {head handler;tail handler;return;}tail.setSuccessor(handler);tail handler;}public void handle() {if (head ! null) {head.handle();}}
}// 使用举例
public class Application {public static void main(String[] args) {HandlerChain chain new HandlerChain();chain.addHandler(new HandlerA());chain.addHandler(new HandlerB());chain.handle();}
}这段代码和上面的代码实现的是相同的职责链模式只是实现的方式略有不同。具体区别如下
上面的代码中抽象处理器 Handler 类的 doHandle() 方法返回 boolean 类型表示是否处理了请求而这里的代码中抽象处理器 Handler 类的 doHandle() 方法返回 void 类型表示无论是否处理请求都会执行该方法。在上面的代码中处理器链中的处理器如果处理了请求则不会继续往后传递请求而在这里的代码中处理器链中的处理器不管是否处理了请求都会把请求继续传递给下一个处理器。
总的来说这两段代码的区别并不大都是实现职责链模式的有效方式具体的实现方式可以根据实际情况进行选择。
使用数组实现
public class HandlerChain {private final ListHandler handlers new ArrayList();public void addHandler(Handler handler) {handlers.add(handler);}public void handle() {for (Handler handler : handlers) {handler.handle();}}
}
这个改进方案的主要变化如下
将处理器链的存储方式从链表改为了数组这样可以更加高效地遍历所有处理器。去掉了 tail 指针因为数组可以直接按照添加的顺序来遍历不需要链表的指针。在 handle() 方法中直接使用 for 循环来遍历所有处理器不需要链表中的递归调用。
这种改进方案的优点是代码更加简洁易懂效率也更高。但是需要注意的是这种方式只适用于处理器数量不太多的情况如果处理器数量很大那么这种方式的效率可能会受到影响因为数组的大小是固定的如果处理器数量很大可能会导致数组空间的浪费。
应用场景
日志输出
当然这里是一个类似于日志记录框架的职责链模式的例子。假设我们有一个需求需要在应用程序中使用多个记录器例如控制台记录器、文件记录器和电子邮件记录器将日志信息记录在不同的位置那么我们可以使用职责链模式来实现这个功能。
// Interface for all loggers in the chain
public interface Logger {void log(String message);
}// Logger implementation that writes to console
public class ConsoleLogger implements Logger {Overridepublic void log(String message) {System.out.println(Console Logger: message);}
}// Logger implementation that writes to a file
public class FileLogger implements Logger {Overridepublic void log(String message) {System.out.println(File Logger: message);}
}// Logger implementation that sends an email
public class EmailLogger implements Logger {Overridepublic void log(String message) {System.out.println(Email Logger: message);}
}// The chain that contains all loggers
public class LoggerChain {private ListLogger loggers new ArrayList();public void addLogger(Logger logger) {this.loggers.add(logger);}public void log(String message) {for (Logger logger : loggers) {logger.log(message);}}
}// Usage example
public class ApplicationDemo {public static void main(String[] args) {LoggerChain loggerChain new LoggerChain();loggerChain.addLogger(new ConsoleLogger());loggerChain.addLogger(new FileLogger());loggerChain.addLogger(new EmailLogger());loggerChain.log(This is a log message.);}
}
spring过滤器
Spring Boot Servlet 过滤器Filter在 Web 应用程序中可以使用过滤器来对请求进行处理。Spring Boot Servlet 过滤器使用职责链模式来实现多个过滤器的链式调用。在请求处理过程中过滤器链中的每个过滤器都可以对请求进行处理和修改过滤器链主要用于拦截 HTTP 请求并在请求到达处理器之前对其进行预处理以实现一些共性的处理逻辑例如权限校验、日志记录、字符编码转换等。
public class CharacterEncodingFilter implements Filter {private String encoding;Overridepublic void init(FilterConfig filterConfig) throws ServletException {encoding filterConfig.getInitParameter(encoding);}Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {request.setCharacterEncoding(encoding);chain.doFilter(request, response);}Overridepublic void destroy() {// do nothing}
}
该过滤器的作用是将 HTTP 请求的字符编码设置为指定的编码。它实现了 Filter 接口并重写了init、doFilter和destroy方法。在doFilter方法中该过滤器首先将请求的字符编码设置为指定的编码然后调用 FilterChain 的 doFilter 方法将请求转发给下一个过滤器。
SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}Beanpublic FilterRegistrationBeanCharacterEncodingFilter characterEncodingFilterRegistrationBean() {FilterRegistrationBeanCharacterEncodingFilter registrationBean new FilterRegistrationBean();registrationBean.setFilter(new CharacterEncodingFilter());registrationBean.addUrlPatterns(/*);registrationBean.addInitParameter(encoding, UTF-8);registrationBean.setName(characterEncodingFilter);registrationBean.setOrder(1);return registrationBean;}
}
在上面的代码中我们使用了**Bean注解来声明一个名为characterEncodingFilterRegistrationBean的 Bean。这个 Bean 是一个FilterRegistrationBean**类型的对象它用于将 CharacterEncodingFilter 过滤器注册到应用程序中。
在characterEncodingFilterRegistrationBean方法中
我们首先创建一个FilterRegistrationBean对象并将 CharacterEncodingFilter 过滤器实例作为参数传入。然后我们使用addUrlPatterns方法来指定该过滤器所拦截的 URL 模式。在本例中我们将其设置为拦截所有请求。接下来我们使用addInitParameter方法来设置过滤器的初始化参数。最后我们使用setName方法来指定该过滤器的名称使用setOrder方法来指定该过滤器在过滤器链中的顺序。
通过以上的配置我们就成功地将 CharacterEncodingFilter 过滤器注册到了应用程序中并将其加入到了过滤器链中。当 HTTP 请求到达应用程序时Spring Boot 将会按照过滤器链的顺序依次将请求转发给下一个过滤器直到请求到达处理器。
spirng 拦截器
Spring MVC 拦截器HandlerInterceptor在 Spring MVC 中可以使用拦截器来拦截请求并在处理请求之前或之后执行一些操作。Spring MVC 拦截器使用职责链模式来实现多个拦截器的链式调用。在请求处理过程中拦截器链中的每个拦截器都可以对请求进行处理和修改。
public class SecurityInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 检查用户的权限if (!hasPermission(request)) {// 如果没有权限返回错误信息response.sendError(HttpServletResponse.SC_FORBIDDEN, Forbidden);return false;}return true;}private boolean hasPermission(HttpServletRequest request) {// 检查用户是否具有执行该请求的权限// ...return true;}
}public class LogInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 记录请求日志logRequest(request);return true;}private void logRequest(HttpServletRequest request) {// 记录请求日志// ...}
}public class InterceptorChainConfigurer implements WebMvcConfigurer {Autowiredprivate SecurityInterceptor securityInterceptor;Autowiredprivate LogInterceptor logInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(securityInterceptor);registry.addInterceptor(logInterceptor);}
}
拦截器和过滤器的实现机制中都使用了职责链模式。 在 Spring MVC 中拦截器是通过 HandlerInterceptor 接口实现的它的实现类可以在 Spring MVC 的配置文件中配置并按照顺序组成一个拦截器链。在请求处理过程中拦截器链中的每个拦截器都可以对请求进行处理和修改形成一个职责链。 同样在 Servlet 中过滤器也是使用职责链模式实现的。在 web.xml 中配置的过滤器会按照顺序形成一个过滤器链每个过滤器都可以对请求进行处理和修改形成一个职责链。 因此拦截器和过滤器的实现机制都借鉴了职责链模式的思想通过将多个拦截器或过滤器组合成一个链条实现对请求进行处理和拦截的目的。
在 Spring MVC 中拦截器和过滤器都是用于对请求进行处理和拦截的组件但是它们有一些区别
拦截器是 Spring MVC 框架提供的组件而过滤器是 Servlet 规范提供的组件。因此使用拦截器需要在 Spring MVC 的配置文件中配置拦截器而使用过滤器需要在 web.xml 中配置过滤器。拦截器只能拦截请求并且只能在请求被分派到具体的处理器Controller之前或之后进行处理它不能修改请求的内容。而过滤器可以拦截请求和响应它能够修改请求和响应的内容。拦截器可以访问 Spring MVC 的上下文如请求和响应对象、处理器对象等并可以调用处理器方法。而过滤器只能访问 Servlet 的上下文如请求和响应对象它不能调用处理器方法。拦截器是基于 AOP 实现的可以使用 AOP 的特性如切面、通知等因此它具有更高的灵活性和可扩展性。而过滤器只能使用 Servlet 规范中定义的特性它的灵活性和可扩展性相对较低。
mybatis动态sql
MyBatis 使用 SQLNode 接口来表示 SQL 语句的不同部分例如 WHERE 子句、SET 子句等等。每个 SQLNode 对象都包含一个 SQLNode 的集合这些集合可以被视为一个责任链。在处理 SQL 语句时MyBatis 会按照一定的顺序遍历这个责任链让每个 SQLNode 对象对 SQL 语句进行处理。这样MyBatis 就能够灵活地生成各种不同的 SQL 语句而不需要编写大量的重复代码。 例如当我们执行一个带有条件查询的 SQL 语句时MyBatis 会生成一个带有 WHERE 子句的 SQL 语句。在生成这个 SQL 语句的过程中MyBatis 会依次遍历责任链中的每个 SQLNode 对象并将它们的结果拼接成最终的 SQL 语句。如果某个 SQLNode 对象无法处理当前的 SQL 语句部分它会将处理权交给下一个 SQLNode 对象直到整个责任链被遍历完为止。
public interface SQLNode {String process(String sql);
}public class WhereNode implements SQLNode {private SQLNode next;public WhereNode(SQLNode next) {this.next next;}Overridepublic String process(String sql) {String where WHERE ;if (next ! null) {where next.process(sql);}return where;}
}public class OrderByNode implements SQLNode {private SQLNode next;public OrderByNode(SQLNode next) {this.next next;}Overridepublic String process(String sql) {String orderBy ORDER BY id;if (next ! null) {orderBy next.process(sql);}return orderBy;}
}public class SelectNode implements SQLNode {private SQLNode next;public SelectNode(SQLNode next) {this.next next;}Overridepublic String process(String sql) {String select SELECT * FROM table;if (next ! null) {select next.process(sql);}return select;}
}// 构建责任链
SQLNode whereNode new WhereNode(null);
SQLNode orderByNode new OrderByNode(whereNode);
SQLNode selectNode new SelectNode(orderByNode);// 生成 SQL 语句
String sql selectNode.process(null);
System.out.println(sql);
在这个示例中我们定义了三个 SQLNode 类分别对应 SQL 语句中的 WHERE 子句、ORDER BY 子句和 SELECT 语句。每个 SQLNode 对象都包含一个 next 属性用于指向责任链中的下一个 SQLNode 对象。 我们首先创建了 WhereNode 对象然后创建了 OrderByNode 和 SelectNode 对象并将它们与 WhereNode 对象连接起来形成了一个责任链。最后我们通过调用 selectNode.process(null) 方法来生成 SQL 语句这样 MyBatis 就会按照责任链的顺序遍历各个 SQLNode 对象并将它们的处理结果拼接成最终的 SQL 语句。