天天看点

面试官:责任链和策略设计模式,你确定了解吗,程序员之路真坎坷

作者:互联网技术学堂

引言

责任链(Chain of Responsibility)和策略(Strategy)设计模式是两种经典的行为型设计模式,在 Java 开发中被广泛应用。本文将分析这两种设计模式的使用场景、类图结构、Spring AOP 框架中的应用、责任链设计模式在 Spring AOP 框架中的应用、优势和劣势,以及在 Spring 中体现的点。

大家好,这里是互联网技术学堂,留下你的点赞、关注、分享,您的支持是我创作的源泉,谢谢。

责任链设计模式

使用场景

责任链设计模式适用于一个任务需要多个处理者来处理,但是具体处理任务的处理者在任务提交前无法确定。比如日常生活中的请假流程,一个员工请假需要经过多个领导层级的审批,不同层级的领导有不同的审批权限和决策能力,当一个领导处理不了这个请求时,会将请求传递给下个领导。这个过程就是一个典型的责任链模式。

面试官:责任链和策略设计模式,你确定了解吗,程序员之路真坎坷

类图结构

责任链模式由三个部分组成:抽象处理者、具体处理者和客户端。抽象处理者定义了处理请求的接口,并且维护了一个指向下一个处理者的引用;具体处理者实现了处理请求的具体逻辑,并且可以选择将请求传递给下一个处理者;客户端负责创建责任链,并将请求发送给责任链的首要处理者。

责任链设计模式类图

面试官:责任链和策略设计模式,你确定了解吗,程序员之路真坎坷

Spring AOP 框架中的应用

Spring AOP 框架中的切面(Aspect)就是一个责任链,每个切面都是一个处理者,可以选择处理请求或将请求传递给下一个切面。Spring AOP 框架中的切面可以使用注解或 XML 配置的方式定义,具体实现方式类似于责任链模式中的具体处理者。Spring AOP 框架中的切点(Pointcut)定义了哪些方法需要被切入,可以使用注解或 XML 配置的方式定义,类似于责任链模式中的客户端。

责任链设计模式在 Spring AOP 框架中的应用

Spring AOP 框架中的切面可以使用责任链模式来实现,每个切面都可以选择处理请求或将请求传递给下一个切面。使用责任链模式可以让切面的处理逻辑更加清晰、灵活和可扩展。

面试官:责任链和策略设计模式,你确定了解吗,程序员之路真坎坷

优势和劣势

优势

  • 责任链模式可以将一个任务拆分成多个子任务,每个子任务由一个具体处理者来处理,实现了解耦。
  • 责任链模式可以动态地调整责任链中的处理者。
  • 责任链模式可以避免在客户端中使用大量的 if-else 语句,使代码更加简洁、可维护和可扩展。
  • 责任链模式可以在运行时动态地添加、删除或修改处理者,实现了动态性。

劣势

  • 责任链模式可能存在处理请求的处理者链过长的问题,影响处理性能。
  • 责任链模式可能存在某个处理者无法处理请求的问题,需要谨慎设计处理者链。

在 Spring 中体现的点

在 Spring 中,责任链模式可以通过 AOP 和 Bean Post Processor 来体现。

在 AOP 中,切面就是一个责任链,每个切面都是一个具体处理者,可以选择处理请求或将请求传递给下一个切面。

在 Bean Post Processor 中,可以通过继承 AbstractBeanFactoryPostProcessor 类来实现一个 Bean 处理器的责任链。每个 Bean 处理器都是一个具体处理者,可以选择处理 Bean 或将 Bean 传递给下一个处理器。

Spring AOP 中使用责任链模式的示例代码

@Aspect
public class MyAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
// 执行前置处理
// ...
Object result = pjp.proceed();
// 执行后置处理
// ...
return result;
}
}           

策略设计模式

使用场景

策略设计模式适用于一个任务有多个不同的实现方式,且需要在运行时动态地选择其中一种实现方式。比如日常生活中的出行方式,可以选择骑自行车、坐公交车、打车或开私家车等不同的实现方式,具体选择哪种方式取决于具体情况,如时间、距离、费用等。

面试官:责任链和策略设计模式,你确定了解吗,程序员之路真坎坷

类图结构

策略模式由三个部分组成:策略接口、具体策略和客户端。策略接口定义了所有策略的公共接口,具体策略实现了策略接口中的方法,客户端负责创建策略对象,并在运行时选择具体的策略对象。

策略设计模式类图

面试官:责任链和策略设计模式,你确定了解吗,程序员之路真坎坷

责任链模式示例代码

// 定义抽象处理者
public abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(Request request);
}
// 具体处理者1
public class ConcreteHandler1 extends Handler {
public void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE1) {
// 处理请求
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
// 具体处理者2
public class ConcreteHandler2 extends Handler {
public void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE2) {
// 处理请求
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setSuccessor(handler2);
handler1.handleRequest(new Request(RequestType.TYPE2));
}
}
// 请求类
public class Request {
private RequestType type;
public Request(RequestType type) {
this.type = type;
}
public RequestType getType() {
return type;
}
}
// 请求类型枚举
public enum RequestType {
TYPE1, TYPE2
}           

在上面的代码中,抽象处理者类 Handler 定义了处理请求的抽象方法 handleRequest() 和一个后继处理者 successor,具体处理者类 ConcreteHandler1 和 ConcreteHandler2 继承了抽象处理者类并实现了具体的请求处理方法。客户端代码通过将具体处理者类链接起来并传入一个请求对象来启动整个责任链。

Spring AOP 框架中的应用

在 Spring AOP 框架中,策略模式可以通过使用注解或 XML 配置的方式来实现。使用注解可以通过 @Qualifier 注解来指定具体的策略对象,使用 XML 配置可以通过 <property> 元素来指定具体的策略对象。

面试官:责任链和策略设计模式,你确定了解吗,程序员之路真坎坷

策略设计模式示例代码

// 抽象策略接口
public interface Strategy {
void execute();
}
// 具体策略类1
public class ConcreteStrategy1 implements Strategy {
public void execute() {
// 具体实现
}
}
// 具体策略类2
public class ConcreteStrategy2 implements Strategy {
public void execute() {
// 具体实现
}
}
// 上下文类
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Context context = new Context(new ConcreteStrategy1());
context.executeStrategy();
context.setStrategy(new ConcreteStrategy2());
context.executeStrategy();
}
}           

在上面的代码中,抽象策略接口 Strategy 定义了策略方法 execute(),具体策略类 ConcreteStrategy1 和 ConcreteStrategy2 实现了策略方法。上下文类 Context持有一个策略对象,并在客户端代码中设置具体的策略对象来执行不同的策略。

优势和劣势

优势

策略模式可以在运行时动态地选择具体的实现方式,实现了可扩展性。

策略模式可以避免使用大量的 if-else 语句,使代码更加简洁、可维护和可扩展。

劣势

  • 策略模式需要在客户端显式地创建和选择具体的策略对象,对客户端编码要求较高。
  • 策略模式可能存在多个策略之间重复代码的问题,需要谨慎设计。

在 Spring 中体现的点

在 Spring 中,策略模式可以通过依赖注入和条件注解来体现。

依赖注入可以通过将具体的策略对象注入到客户端中来实现,从而避免客户端显式地创建和选择具体的策略对象。

条件注解可以通过 @Conditional 注解来根据条件选择具体的策略对象。条件注解可以根据环境、配置或其他条件来选择具体的策略对象,实现了更加灵活的策略选择。

Spring AOP 中的策略设计模式应用

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {
String value();
}
@Service
@Strategy("A")
public class StrategyA implements MyStrategy {
public void execute() {
// 具体实现
}
}
@Service
@Strategy("B")
public class StrategyB implements MyStrategy {
public void execute() {
// 具体实现
}
}
@Component
public class StrategyExecutor {
@Autowired
private List<MyStrategy> strategies;
public void execute(String strategyType) {
for (MyStrategy strategy : strategies) {
if (strategy.getClass().isAnnotationPresent(Strategy.class)
&& strategy.getClass().getAnnotation(Strategy.class).value().equals(strategyType)) {
strategy.execute();
}
}
}
}
public interface MyStrategy {
void execute();
}
public class Client {
public static void main(String[] args) {
StrategyExecutor executor = new StrategyExecutor();
executor.execute("A");
}
}           

在上面的代码中,@Strategy 注解用于标注具体的策略类,StrategyExecutor 类持有一个策略列表,并通过 execute() 方法来执行指定的策略。在客户端代码中,可以通过传入不同的参数来执行不同的策略。

总结

责任链模式和策略设计模式都是常用的设计模式,它们可以提高代码的可维护性和可扩展性。在 Spring 中,这两种设计模式可以通过 AOP、Bean Post Processor、依赖注入和条件注解等方式来体现。当需要实现多个处理者的请求处理或多种实现方式的选择时,可以考虑使用责任链模式和策略设计模式。

继续阅读