策略模式与责任链模式学习笔记:从入门到理解

打印 上一主题 下一主题

主题 2051|帖子 2051|积分 6153

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
策略模式与责任链模式学习笔记:从入门到理解

你好!作为一名 Java Web 后端开发工程师,初学设计模式时对不同模式感到困惑是很正常的。策略模式(Strategy Pattern)和责任链模式(Chain of Responsibility Pattern)都是行为型设计模式,它们在某些方面有相似之处,但也存在显着的区别。这篇笔记将帮助你从头梳理这两种设计模式,并通过生存中的例子和代码示例,让你更清晰地理解它们以及何时选择使用。
一、策略模式 (Strategy Pattern)

1. 什么是策略模式?

想象一下,你在计划一次出行,从家到公司,你可以选择多种交通方式:挤公交、坐地铁、打出租车或者骑共享单车。每种方式都是一种策略,详细选择哪种策略取决于当时的情况(比如时间、天气、预算等)。
策略模式的定义:它定义了算法家属,分别封装起来,让它们之间可以互相替换。此模式让算法的变化独立于使用算法的客户。
简单来说,策略模式就是将这些不同的“出行方式”(算法)封装成独立的类,让你可以动态地选择使用哪一种。
2. 生存中的例子



  • 支付方式:在电商网站购物,结账时可以选择支付宝支付、微信支付、银行卡支付、花呗分期等,每一种支付方式就是一种策略。
  • 文件压缩:压缩软件可以使用不同的压缩算法,如 ZIP、RAR、7Z,用户可以选择其中一种策略进行压缩。
  • 排序算法:对一个数据集进行排序,可以选择冒泡排序、快速排序、归并排序等,每种排序算法也是一种策略。
  • 导航软件的路线规划:导航软件会提供多种路线策略,如“时间最短”、“路程最短”、“避开高速”等。
3. 策略模式的布局

策略模式重要包罗以下三个角色:


  • Context (上下文情况):它持有一个对策略对象的引用,并终极调用策略对象的方法。它不关心详细的策略是什么,只负责在运行时接收或设置一个详细的策略,然后将请求委托给当前选中的策略。
  • Strategy (抽象策略):这是一个接口或抽象类,定义了所有支持的算法的公共接口。Context 使用这个接口来调用某个详细策略定义的算法。
  • ConcreteStrategy (详细策略):实现了 Strategy 接口,封装了详细的算法或行为。每个详细策略类代表一种算法实现。
(用笔墨描述布局关键点)


  • 你会有一个 Strategy 接口,内里定义了一个方法,比如 executeAlgorithm()。
  • 然后有很多个实现了 Strategy 接口的 ConcreteStrategyA, ConcreteStrategyB 类,它们各自实现了 executeAlgorithm() 方法,代表不同的算法。
  • 最后有一个 Context 类,它内部维护一个 Strategy 类型的成员变量。Context 类有一个方法可以让客户端设置详细使用哪个 ConcreteStrategy,另有一个方法会调用当前 Strategy 对象的 executeAlgorithm() 方法。
4. 代码示例:电商促销运动

假设我们有一个电商系统,针对不同的促销运动(如无优惠、满减、打折),需要计算订单的终极代价。
不使用策略模式的写法 (原始写法):
  1. public class OrderOriginal {
  2.     private String promotionType; // 活动类型: "NONE", "CASH_RETURN", "REBATE"
  3.     private double originalPrice;
  4.     public OrderOriginal(String promotionType, double originalPrice) {
  5.         this.promotionType = promotionType;
  6.         this.originalPrice = originalPrice;
  7.     }
  8.     public double calculateFinalPrice() {
  9.         double finalPrice = originalPrice;
  10.         if ("NONE".equals(promotionType)) { // 无优惠
  11.             // finalPrice 保持原价
  12.         } else if ("CASH_RETURN".equals(promotionType)) { // 满减,例如满200减20
  13.             if (originalPrice >= 200) {
  14.                 finalPrice = originalPrice - 20;
  15.             }
  16.         } else if ("REBATE".equals(promotionType)) { // 打折,例如打9折
  17.             finalPrice = originalPrice * 0.9;
  18.         }
  19.         // 如果再增加新的促销方式,比如“第二件半价”,就需要继续修改这里的 if-else
  20.         // 这违反了开闭原则,代码会越来越臃肿,难以维护
  21.         return finalPrice;
  22.     }
  23.     public static void main(String[] args) {
  24.         OrderOriginal order1 = new OrderOriginal("NONE", 150);
  25.         System.out.println("无优惠,最终金额: " + order1.calculateFinalPrice());
  26.         OrderOriginal order2 = new OrderOriginal("CASH_RETURN", 250);
  27.         System.out.println("满200减20,最终金额: " + order2.calculateFinalPrice());
  28.         OrderOriginal order3 = new OrderOriginal("REBATE", 300);
  29.         System.out.println("打9折,最终金额: " + order3.calculateFinalPrice());
  30.     }
  31. }
复制代码
缺点:calculateFinalPrice 方法布满了 if-else 判断。每当需要增加一种新的促销策略时,都必须修改这个方法的内部逻辑,违反了“开闭原则”(对扩睁开放,对修改关闭),而且使得这个类越来越庞大,难以维护。
使用策略模式的写法:
步调1:定义策略接口 (PromotionStrategy)
  1. // 抽象策略:促销策略接口
  2. interface PromotionStrategy {
  3.     double applyPromotion(double originalPrice);
  4. }
复制代码
步调2:创建详细策略类
  1. // 具体策略A:无优惠
  2. class NoPromotionStrategy implements PromotionStrategy {
  3.     @Override
  4.     public double applyPromotion(double originalPrice) {
  5.         System.out.println("执行无优惠策略");
  6.         return originalPrice;
  7.     }
  8. }
  9. // 具体策略B:满减策略 (例如:满200减20)
  10. class CashReturnStrategy implements PromotionStrategy {
  11.     private double conditionAmount;
  12.     private double returnAmount;
  13.     public CashReturnStrategy(double conditionAmount, double returnAmount) {
  14.         this.conditionAmount = conditionAmount;
  15.         this.returnAmount = returnAmount;
  16.     }
  17.     @Override
  18.     public double applyPromotion(double originalPrice) {
  19.         System.out.println("执行满" + conditionAmount + "减" + returnAmount + "策略");
  20.         if (originalPrice >= conditionAmount) {
  21.             return originalPrice - returnAmount;
  22.         }
  23.         return originalPrice;
  24.     }
  25. }
  26. // 具体策略C:打折策略 (例如:9折)
  27. class RebateStrategy implements PromotionStrategy {
  28.     private double rebateRate; // 例如0.9代表9折
  29.     public RebateStrategy(double rebateRate) {
  30.         this.rebateRate = rebateRate;
  31.     }
  32.     @Override
  33.     public double applyPromotion(double originalPrice) {
  34.         System.out.println("执行" + (rebateRate * 10) + "折策略");
  35.         return originalPrice * rebateRate;
  36.     }
  37. }
复制代码
步调3:创建上下文情况类 (OrderContext)
  1. // 上下文环境类
  2. class OrderContext {
  3.     private PromotionStrategy strategy;
  4.     private double originalPrice;
  5.     // 构造函数,传入订单原始价格
  6.     public OrderContext(double originalPrice) {
  7.         this.originalPrice = originalPrice;
  8.     }
  9.     // 设置具体策略
  10.     public void setPromotionStrategy(PromotionStrategy strategy) {
  11.         this.strategy = strategy;
  12.     }
  13.     // 调用策略方法计算价格
  14.     public double getFinalPrice() {
  15.         if (this.strategy == null) {
  16.             // 默认策略或抛出异常
  17.             System.out.println("未设置促销策略,默认无优惠");
  18.             this.strategy = new NoPromotionStrategy();
  19.         }
  20.         return strategy.applyPromotion(originalPrice);
  21.     }
  22. }
复制代码
步调4:客户端使用
  1. public class StrategyPatternClient {
  2.     public static void main(String[] args) {
  3.         // 订单1:150元,使用无优惠策略
  4.         OrderContext order1 = new OrderContext(150);
  5.         order1.setPromotionStrategy(new NoPromotionStrategy());
  6.         System.out.println("订单1最终金额: " + order1.getFinalPrice());
  7.         System.out.println("--------------------");
  8.         // 订单2:250元,使用满200减20策略
  9.         OrderContext order2 = new OrderContext(250);
  10.         order2.setPromotionStrategy(new CashReturnStrategy(200, 20));
  11.         System.out.println("订单2最终金额: " + order2.getFinalPrice());
  12.         System.out.println("--------------------");
  13.         // 订单3:300元,使用打9折策略
  14.         OrderContext order3 = new OrderContext(300);
  15.         order3.setPromotionStrategy(new RebateStrategy(0.9));
  16.         System.out.println("订单3最终金额: " + order3.getFinalPrice());
  17.         System.out.println("--------------------");
  18.         // 假设现在要新增一个“首单立减10元”的策略
  19.         // 只需要新增一个 FirstOrderDiscountStrategy 类实现 PromotionStrategy 接口:
  20.         // class FirstOrderDiscountStrategy implements PromotionStrategy {
  21.         //     @Override
  22.         //     public double applyPromotion(double originalPrice) {
  23.         //         System.out.println("执行首单立减10元策略");
  24.         //         return originalPrice - 10 > 0 ? originalPrice - 10 : 0;
  25.         //     }
  26.         // }
  27.         // 然后客户端就可以这样使用:
  28.         // OrderContext order4 = new OrderContext(100);
  29.         // order4.setPromotionStrategy(new FirstOrderDiscountStrategy());
  30.         // System.out.println("订单4最终金额: " + order4.getFinalPrice());
  31.         // 此时,OrderContext 和 PromotionStrategy 接口都不需要修改,符合开闭原则。
  32.     }
  33. }
复制代码
使用策略模式的长处:


  • 算法可以自由切换:在运行时可以方便地根据需求切换不同的促销策略。
  • 避免了多重条件判断:消除了 OrderContext (或原先的 OrderOriginal) 中冗长的 if-else 或 switch-case 语句。
  • 扩展性好:增加新的促销策略非常容易,只需要添加一个新的详细策略类实现 PromotionStrategy 接口即可,完全符合开闭原则。
  • 每个算法都有自己的类,复用性进步:每个策略都是一个独立的类,职责清晰,易于测试和复用。
  • 代码更清晰:上下文类只负责协调,详细的业务逻辑在各个策略类中。
5. 策略模式的适用场景



  • 当一个系统需要在多种算法中选择一种时,可以将这些算法封装成独立的策略类。
  • 当一个对象拥有多种行为,而且这些行为在运行时根据不同情况动态选择时。
  • 当一个类中存在多个条件分支语句,且这些分支封装了不同的操纵时(这是重构的信号)。
  • 当需要屏蔽算法规则或业务规则的复杂性,让客户端代码更简便时。
6. 策略模式的优缺点

长处:


  • 策略类可以互相替换,使得算法的选择更加灵活。
  • 易于扩展,增加新的策略只需要添加新的策略类,符合开闭原则。
  • 避免了使用多重条件转移语句(if-else, switch)。
  • 进步了算法的保密性和安全性,由于详细的算法实现细节封装在策略类内部,客户端不需要相识。
缺点:


  • 策略类数量增多:每个详细策略都是一个类,如果策略很多,会导致类的数量增加。
  • 客户端必须知道所有的策略类:客户端(或配置代码)需要相识所有可用的策略以及它们之间的不同,才能在合适的机遇选择合适的策略。可以通过结合工厂模式、依赖注入等方式来管理策略对象的创建和选择,以减轻客户端的职责。
二、责任链模式 (Chain of Responsibility Pattern)

1. 什么是责任链模式?

想象一下公司里的请假审批流程:你提交请假单,首先需要你的小组长审批。如果请假天数在小组长权限内(比如1天),小组长可以直接批准。如果天数较长(比如3天),小组长处置惩罚不了(或者说只能部分同意,然后上报),就需要将请求转达给部门经理审批。如果天数更长(比如7天),部门经理可能还需要将请求继承转达给总监审批。这个审批过程就像一条链条,你的请假请求在这条链上转达,每个审批人只关心自己职责范围内的事变,如果能处置惩罚就处置惩罚,不能处置惩罚就交给链上的下一个人。
责任链模式的定义:使多个对象都有机会处置惩罚请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链转达该请求,直到有一个对象处置惩罚它为止(或者所有对象都处置惩罚了它,或者链断了)。
简单来说,责任链模式就是为请求创建了一个接收者对象的链,请求会沿着链转达,直到链上的某个处置惩罚者处置惩罚它,或者请求穿过整个链条。
2. 生存中的例子



  • Java Web 中的 Filter 链:一个 HTTP 请求过来,可能需要颠末多个 Filter 处置惩罚,如日志记载 Filter、权限校验 Filter、字符编码 Filter 等。每个 Filter 完成自己的使命后,可以选择将请求转达给链上的下一个 Filter,或者直接相应。
  • 非常处置惩罚机制:Java 的 try-catch-finally 语句块,如果一个 try 块中发生非常,会先被第一个 catch 块尝试捕获,如果类型不匹配或处置惩罚不了,可以重新抛出,由外层的 catch 或JVM默认非常处置惩罚器(链的末了)处置惩罚。
  • OA 系统的审批流程:采购申请、报销申请等,通常需要颠末多个级别的审批者依次审批。
  • 事件冒泡/捕获机制:在图形用户界面(GUI)编程中,一个组件上的事件(如点击)可能会先由该组件处置惩罚,如果未处置惩罚,则向上转达给其父组件处置惩罚。
3. 责任链模式的布局

责任链模式重要包罗以下角色:


  • Handler (抽象处置惩罚者):定义了一个处置惩罚请求的接口(通常是一个方法 handleRequest(request)),而且持有一个指向链中下一个处置惩罚者(后继者)的引用。
  • ConcreteHandler (详细处置惩罚者):实现了 Handler 接口。它负责处置惩罚它所能处置惩罚的请求。在 handleRequest 方法中,它会判断自己是否能处置惩罚该请求:

    • 如果可以处置惩罚,则处置惩罚请求,并可能决定是否继承转达给下一个处置惩罚者。
    • 如果不能处置惩罚,则将请求转发给它的后继者(如果存在)。

  • Client (客户端):创建处置惩罚链(即组装 ConcreteHandler 对象),并向链头的处置惩罚者发起请求。客户端通常不关心请求终极由哪个详细处置惩罚者处置惩罚。
(用笔墨描述布局关键点)


  • 你会有一个 Handler 接口或抽象类,内里定义了一个处置惩罚请求的方法 handleRequest(request),以及一个设置下一个处置惩罚者的方法 setNextHandler(handler)。通常,Handler 内部会有一个 Handler nextHandler 成员变量来保存下一个处置惩罚者的引用。
  • 然后有很多个 ConcreteHandlerA, ConcreteHandlerB 类,它们实现了 Handler。在 handleRequest 方法中,它们会先判断自己能否处置惩罚这个请求。如果能,就处置惩罚,并决定是否到此为止;如果不能(或者处置惩罚完还想让别人也处置惩罚),就调用 nextHandler.handleRequest(request) 把请求转达下去(固然,要先判断 nextHandler 是否为空)。
  • 客户端会创建这些 ConcreteHandler 对象,并调用它们的 setNextHandler 方法把它们串联起来形成一条链。然后客户端将请求发送给链的第一个处置惩罚者。
4. 代码示例:敏感词过滤器链

假设我们需要对用户发表的评论进行敏感词过滤,不同类型的敏感词(如政治类、广告类)由不同的过滤器处置惩罚。每个过滤器处置惩罚完自己负责的部分后,将内容交给下一个过滤器继承处置惩罚。
不使用责任链模式的写法 (原始写法):
  1. public class CommentProcessorOriginal {
  2.     public String filter(String comment) {
  3.         String processedComment = comment;
  4.         // 过滤政治敏感词
  5.         if (processedComment.contains("敏感词A")) {
  6.             processedComment = processedComment.replace("敏感词A", "***");
  7.         }
  8.         // 过滤广告词
  9.         if (processedComment.contains("广告词X")) {
  10.             processedComment = processedComment.replace("广告词X", "$$$");
  11.         }
  12.         // 如果增加新的过滤规则,比如色情词过滤,就需要不断修改这个方法
  13.         // 职责不单一,代码耦合度高
  14.         return processedComment;
  15.     }
  16.     public static void main(String[] args) {
  17.         CommentProcessorOriginal processor = new CommentProcessorOriginal();
  18.         String comment = "这是一条包含敏感词A和广告词X的评论。";
  19.         String filteredComment = processor.filter(comment);
  20.         System.out.println("原始评论: " + comment);
  21.         System.out.println("过滤后评论: " + filteredComment);
  22.     }
  23. }
复制代码
缺点:filter 方法职责过重,包罗了所有类型的过滤逻辑。新增或修改过滤规则都需要改动这个方法,违反开闭原则,且代码会越来越复杂和难以维护。
使用责任链模式的写法:
步调1:定义抽象处置惩罚者 (CommentFilter)
  1. // 抽象处理者:评论过滤器
  2. abstract class CommentFilter {
  3.     protected CommentFilter nextFilter; // 指向下一个过滤器
  4.     public void setNextFilter(CommentFilter nextFilter) {
  5.         this.nextFilter = nextFilter;
  6.     }
  7.     // 处理请求的方法
  8.     // 返回处理后的评论内容,或者也可以设计成直接修改传入的 Comment 对象
  9.     public abstract String doFilter(String comment);
  10. }
复制代码
步调2:创建详细处置惩罚者类
  1. // 具体处理者A:政治敏感词过滤器
  2. class PoliticalWordFilter extends CommentFilter {
  3.     @Override
  4.     public String doFilter(String comment) {
  5.         System.out.println("执行政治敏感词过滤...");
  6.         String filteredComment = comment.replace("敏感词A", "***").replace("反动", "##");
  7.         
  8.         // 如果有下一个过滤器,则继续传递给下一个过滤器处理
  9.         if (nextFilter != null) {
  10.             return nextFilter.doFilter(filteredComment);
  11.         }
  12.         return filteredComment; // 如果是链的末尾,则返回结果
  13.     }
  14. }
  15. // 具体处理者B:广告词过滤器
  16. class AdvertisementWordFilter extends CommentFilter {
  17.     @Override
  18.     public String doFilter(String comment) {
  19.         System.out.println("执行广告词过滤...");
  20.         String filteredComment = comment.replace("广告词X", "$$$").replace("优惠券", "###");
  21.         
  22.         if (nextFilter != null) {
  23.             return nextFilter.doFilter(filteredComment);
  24.         }
  25.         return filteredComment;
  26.     }
  27. }
  28. // 具体处理者C:特殊字符过滤器 (新增的)
  29. class SpecialCharacterFilter extends CommentFilter {
  30.     @Override
  31.     public String doFilter(String comment) {
  32.         System.out.println("执行特殊字符过滤...");
  33.         String filteredComment = comment.replaceAll("[<>]", ""); // 移除尖括号
  34.         
  35.         if (nextFilter != null) {
  36.             return nextFilter.doFilter(filteredComment);
  37.         }
  38.         return filteredComment;
  39.     }
  40. }
复制代码
步调3:客户端构建责任链并使用
  1. public class ChainOfResponsibilityClient {
  2.     public static void main(String[] args) {
  3.         String comment = "这是一条<包含>敏感词A、广告词X和反动言论的评论,快来领取优惠券!";
  4.         System.out.println("原始评论: " + comment);
  5.         System.out.println("--------------------");
  6.         // 构建过滤器链
  7.         CommentFilter politicalFilter = new PoliticalWordFilter();
  8.         CommentFilter advertisementFilter = new AdvertisementWordFilter();
  9.         CommentFilter specialCharFilter = new SpecialCharacterFilter();
  10.         // 设置链的顺序: 特殊字符 -> 政治敏感 -> 广告
  11.         // 顺序很重要,不同的顺序可能导致不同的结果
  12.         specialCharFilter.setNextFilter(politicalFilter);
  13.         politicalFilter.setNextFilter(advertisementFilter);
  14.         // advertisementFilter 是链的末端,它的 nextFilter 是 null
  15.         // 从链头开始处理
  16.         String filteredComment = specialCharFilter.doFilter(comment);
  17.         System.out.println("--------------------");
  18.         System.out.println("过滤后评论: " + filteredComment);
  19.         // 优点:
  20.         // 1. 新增过滤器非常方便,例如新增一个Emoji过滤器,只需要实现CommentFilter,然后插入链中即可。
  21.         //    现有的过滤器代码完全不需要修改。
  22.         // 2. 每个过滤器的职责单一,易于维护和测试。
  23.         // 3. 过滤器的顺序可以灵活调整。
  24.     }
  25. }
复制代码
使用责任链模式的长处:


  • 降低耦合度:请求的发送者和接收者解耦。发送者不需要知道请求会被哪个接收者处置惩罚,只需将请求发送给链的第一个处置惩罚者。
  • 增强了系统的可扩展性:可以很容易地增加新的处置惩罚者到链中,或改变链中处置惩罚者的次序,符合开闭原则。
  • 增强了给对象指派职责的灵活性:通过改变链内的成员或者变更它们的次序,答应动态地新增或者删除责任,以及动态地改变责任的次序。
  • 简化了对象:使得每个处置惩罚者对象不需要知道链的整体布局,只需要知道它的后继者。
  • 每个类只专注于自己的职责:每个详细处置惩罚者类只负责处置惩罚它能处置惩罚的请求,职责清晰。
5. 责任链模式的适用场景



  • 有多个对象可以处置惩罚同一个请求,详细哪个对象处置惩罚该请求由运行时动态确定(即请求的处置惩罚者不确定)。
  • 在不明白指定接收者的情况下,向多个对象中的一个提交一个请求。
  • 可动态指定一组对象处置惩罚请求,或者添加新的处置惩罚者到这条链上。
  • 例如:Web 应用的过滤器链 (Servlet Filters, Spring Interceptors)、UI 事件的转达与处置惩罚、工作流审批系统、日志记载器的不同级别处置惩罚。
6. 责任链模式的优缺点

长处:


  • 请求的发送者和接收者解耦。
  • 可以动态地组合责任链,灵活地增加或修改处置惩罚一个请求的布局温次序。
  • 易于扩展新的请求处置惩罚者。
  • 每个处置惩罚者职责单一。
缺点:


  • 请求不肯定被处置惩罚:不能保证请求肯定会被链中的某个处置惩罚者处置惩罚。如果没有任何处置惩罚者处置惩罚该请求,请求可能会到达链的末尾仍未被处置惩罚(需要有相应的默认处置惩罚机制或明白链尾行为)。
  • 性能题目:如果责任链过长,或者每个处置惩罚者的处置惩罚逻辑都比较耗时,请求在链中逐级转达可能会对性能产生影响。
  • 调试不方便:由于请求的路径是动态组合的,如果责任链比较长,在调试时可能需要跟踪整个链条的执行过程,增加了调试的复杂性。
  • 可能导致链的构建比较复杂:尤其是在复杂的场景下,链的组织和维护可能需要细致设计。
三、策略模式 vs. 责任链模式

现在我们来对比一下这两种设计模式,希望能帮你更好地理解它们的区别和适用场景。
特性策略模式 (Strategy Pattern)责任链模式 (Chain of Responsibility Pattern)核心头脑封装可互换的行为(算法),客户端或上下文主动选择一个策略来执行。构建对象链,请求在链上自动转达,直到被某个对象处置惩罚(或链结束)。目的使得算法可以独立于使用它的客户端而变化。提供多种方案供选择。避免请求发送者与接收者耦合,让多个对象都有机会处置惩罚请求,形成处置惩罚流程。处置惩罚者数量一个请求通常只由一个选定的详细策略对象处置惩罚。一个请求可能被链上的多个处置惩罚者依次处置惩罚(如果设计如此,如Filter),或被某一个处置惩罚者完备处置惩罚后停止转达(如审批流程)。对象间关系Context 持有对 Strategy 的引用。策略之间通常是平行的、独立的,可互相替换。Handler 持有对下一个 Handler 的引用,形成链式(线性)布局。处置惩罚者之间有明白的先后次序。选择/触发方式客户端或 Context 在运行时明白选择或设置一个详细的策略。请求沿着链自动转达,由链上的对象自行判断是否处置惩罚以及是否继承转达。关注点怎样封装一组可互换的算法,以及怎样根据情况选择和切换算法。怎样组织和转达请求,怎样解耦请求的发送和接收,以及怎样让多个对象协同处置惩罚请求。数据流向Context 将使命委托给(或调用)选定的 Strategy。请求从链头开始,沿着链转达给后续的 Handler是否保证处置惩罚选定的策略肯定会执行其操纵(除非策略自己设计为不执行或有条件执行)。不肯定保证请求会被处置惩罚(如果链中没有合适的处置惩罚者且链尾没有默认处置惩罚)。典范场景多种支付方式、多种排序算法、多种出行路线。Web请求过滤器链、审批流程、日志分级处置惩罚、非常捕获链。类比像一个工具箱,内里有各种工具(策略),用的时候选一个合适的。像工厂流水线,产品(请求)颠末一道道工序(处置惩罚者)。 何时选择哪种模式?


  • 选择策略模式的场景:

    • 当你有一系列相干的算法或行为,它们可以互换使用。
    • 当你希望客户端可以大概在运行时选择使用哪种算法/行为。
    • 当你希望将算法的实现细节与使用算法的代码分脱离来,避免大量的 if-else 或 switch 语句。
    • 核心是“选择”:针对一个使命,有多种独立的、同等的处置惩罚方案,你需要根据情况选择一种。

  • 选择责任链模式的场景:

    • 当一个请求需要被多个对象中的一个或多个处置惩罚,但你事先不知道应该由哪个对象来处置惩罚,或者希望处置惩罚者可以动态组合。
    • 当你希望将请求的发送者和接收者解耦。
    • 当你希望一个请求可以被多个对象按次序部分处置惩罚(像过滤器那样)。
    • 当你希望可以大概动态地改变处置惩罚者的次序或增删处置惩罚者。
    • 核心是“转达”和“分担责任”:一个请求过来,需要颠末一系列可能的处置惩罚环节,每个环节决定自己是否处置惩罚以及是否继承转达。

一个简单的区分思路:


  • 策略模式是“我有多种方法可以做这件事,你(或我根据情况)选一种来用吧!” (One of many options is CHOSEN)
  • 责任链模式是“这件事来了,大家按次序看看谁能处置惩罚,或者每个人都处置惩罚一下自己负责的部分。” (Request is PASSED along a chain)
四、总结重点

对于初学者来说,理解设计模式的关键在于把握其核心头脑、布局和适用场景。


  • 策略模式 (Strategy Pattern)

    • 核心:封装一组可以相互替换的算法(策略)。
    • 目的:使得算法的选择可以独立于使用算法的客户端。
    • 关键布局:抽象策略 (Interface/Abstract Class),详细策略 (Concrete Classes),上下文 (Context class holding a strategy instance)。
    • 长处:易于扩展新策略、消除条件语句、算法独立封装。
    • 思考:当一件事变有多种处置惩罚“方案”或“策略”时,而且这些方案可以互换,可以考虑策略模式。客户端通常主动选择或被配置使用某个特定策略。

  • 责任链模式 (Chain of Responsibility Pattern)

    • 核心:将请求的发送者和接收者解耦,使多个对象都有机会处置惩罚请求,并将这些对象连成一条链。
    • 目的:请求沿着链转达,直到有一个对象处置惩罚它为止(或到达链尾)。
    • 关键布局:抽象处置惩罚者 (Handler Interface/Abstract Class with a successor reference),详细处置惩罚者 (Concrete Handlers implementing the logic and forwarding)。
    • 长处:解耦发送者和接收者、灵活组合处置惩罚流程、职责单一化。
    • 思考:当一个请求的处置惩罚过程可能需要颠末多个步调/对象,这些步调/对象可以动态组合,而且每个步调/对象只关心自己的部分责任时,可以考虑责任链模式。请求通常是自动在链上转达。

学习建议:

  • 多看例子:结合生存中的例子和代码例子去理解模式的意图和布局。
  • 动手实践:尝试在你自己的小型项目或训练中运用这些模式,这是加深理解的最好方式。
  • 思考辨析:对于相似的模式(如策略模式和状态模式,责任链模式和装饰器模式等),多对比它们的意图、布局和适用场景的差别。
  • 循规蹈矩:设计模式的学习是一个逐步深入的过程,不必急于求成。先理解基础的,再逐步学习更复杂的组合和应用。
  • 关注“变化点”:设计模式每每是为了封装系统中可能发生变化的部分,理解一个模式要办理的是哪种类型的变化,有助于你判断何时使用它。
希望这篇笔记能帮助你更好地理解策略模式和责任链模式!在后续的开发工作中,尝试用设计模式的眼光去审视和设计你的代码,你会发现它们能让你的代码更加优雅、健壮和易于维护。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

河曲智叟

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表