当前位置: 首页 > news >正文

23种设计模式-行为型模式-策略

文章目录

  • 简介
  • 场景
  • 解决
    • 代码
    • 关键实现细节
  • 总结

简介

策略是一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类中,以使算法对象能够被替换。

场景

你在开发一款导航应用,类似高德。你要实现自动路线规划的功能:希望输入地址后就能在地图上看到前往目的地的最快路线。
程序的首个版本只能规划公路路线,只适合自驾的人。为了尽量向高德靠拢,你想添加规划步行路线的功能。之后,可能还要添加规划公交地铁路线的功能。过不久可能还要给骑行者规划路线。又过了一段时间,可能还要给城市中的所有景点提供游览路线。
导航代码将变得非常臃肿。

这时你发现,每次添加新的路线规划算法后,导航应用中主要类的体积就会增加一倍。代码就越来越难维护。
无论是修复简单缺陷还是微调街道权重,对某个算法进行任何修改都会影响整个类,从而增加了在已有正常代码中引入错误的风险。
另外,团队合作也非常低效。如果应用由一个团队开发,开发者会在合并冲突的工作上花费很长时间。在实现新功能的过程中,团队需要修改同一个巨大的类,很容易出现冲突。

解决

策略模式建议找出用不同方式完成特定任务的类,然后把里面的算法抽取到一组叫做策略的独立类里。
名叫上下文的原始类必须包含一个成员变量来存储对于每种策略的引用。上下文并不执行任务,而是把工作委派给引用的策略对象。
上下文不负责选择符合任务需要的算法——客户端会把所需策略传递给上下文。实际上,上下文并不了解策略细节,它会通过同样的通用接口跟所有策略交互,这个接口只需要暴露一个方法供上下文调用,具体策略会在这个方法中封装特定算法。
因此,上下文可以独立于具体策略。这样你就可在不修改上下文代码或其他策略的情况下添加新算法或修改已有算法了。
路线规划策略。
在导航应用里,每个路线规划算法都可以被抽取到 只有一个build­Route生成路线方法的 独立类里。这个方法接收起点和终点作为参数,并返回路线途径点的集合。
就算传递给每个路径规划类的参数一模一样,它创建的路线也可能完全不同。导航类的主要工作是在地图上渲染一系列中途点,不会在意如何选择算法。这个类中还有一个用于切换当前路径规划策略的方法,因此客户端(例如用户界面中的切换按钮)可用其他策略替换当前选择的路径规划行为。

代码

// Strategy 接口
interface NavigationStrategy {
    List<String> buildRoute(String start, String end);  // 路由算法接口
}

// 具体策略实现
class WalkingStrategy implements NavigationStrategy {
    @Override 
    public List<String> buildRoute(String start, String end) {  // 步行策略
        return List.of(start, "→ Central Park", "→ 5th Ave", end);  // 步行路线
    }
}

class BusTourStrategy implements NavigationStrategy {
    @Override
    public List<String> buildRoute(String start, String end) {  // 巴士路线策略
        return List.of(start, "→ Bus Stop A", "→ Bus Terminal", end);  // 公交路线 
}
}

class HelicopterStrategy implements NavigationStrategy {
    @Override
    public List<String> buildRoute(String start, String end) {  // 飞行路线策略
        return List.of(start, "→ Airport", "→ "+end+" Airspace", end);  // 空中路线 
    }
}

// 上下文类
class TourGuide {
    private NavigationStrategy strategy;

    public void setStrategy(NavigationStrategy strategy) {  // 运行时切换策略 
        this.strategy = strategy; 
    }

    public void showRoute(String start, String end) {  // 统一入口方法
        if(strategy == null) {
            System.out.println("请先选择导览策略");
            return;
        }
        
        List<String> checkpoints = strategy.buildRoute(start, end);  // 委托策略执行 
        System.out.println("建议路线:");
        checkpoints.forEach(point -> System.out.println("▪ " + point));
    }
}

// 客户端示例
public class Client {
    public static void main(String[] args) {
        TourGuide app = new TourGuide();
        Scanner input = new Scanner(System.in);
        System.out.println("请选择导览模式:\n1.步行 2.巴士 3.直升机");
        
        int choice = input.nextInt();  // 动态选择策略 
        switch(choice) {
            case 1:
                app.setStrategy(new WalkingStrategy());  // 绑定步行策略 
                break;
            case 2:
                app.setStrategy(new BusTourStrategy());
                break;
            case 3:
                app.setStrategy(new HelicopterStrategy());
                break;
            default:
                throw new IllegalArgumentException("无效选择");
        }
        
        app.showRoute("时代广场", "自由女神像");  // 执行所选策略 
    }
}

关键实现细节

  1. 策略切换机制:通过setStrategy方法动态绑定策略对象
  2. 算法封装:每个具体策略类自行实现路径生成算法
  3. 正交扩展:新增导航策略无需修改现有代码(如可添加BicycleStrategy)
  4. 接口统一:所有策略实现相同的buildRoute方法签名

总结

在这里插入图片描述

  1. 上下文(Con­text)维护指向具体策略的引用,且只通过策略接口与策略对象进行交流。
  2. 策略(Strat­e­gy)接口是所有具体策略的通用接口,它声明了一个上下文用于执行策略的方法。
  3. 具体策略(Con­crete Strate­gies)实现了上下文所用算法的各种不同变体。
  4. 当上下文需要运行算法时,它会调用策略对象的方法。上下文不清楚它所涉及的策略类型与算法的执行方式。
  5. 客户端(Client)会创建一个特定策略对象并把他传递给上下文。上下文会提供一个设置器以便客户端在运行时替换相关联的策略。

相关文章:

  • ABAP,PDF,ADS,FORM,PRINT
  • Linux进程概念及理解
  • [创业之路-362]:用确定性的团队、组织、产品开发流程和方法,应对客户、市场、竞争和商业模式的不确定性。
  • CAS与sychronized优化
  • 10. 工具(Tools)集成:连接API、数据库与外部服务的桥梁
  • 8.方法引用综合小练习2-获取部分属性并收集到数组
  • 解读typescript中class类
  • Springboot JPA ShardingSphere 根据年分表java详细代码Demo
  • Java Stream API:现代化集合处理的艺术
  • AI比人脑更强,因为被植入思维模型【49】冰山理论思维模型
  • 鱼骨图分析法实战:5步定位系统故障
  • Linux系统学习Day2——在Linux系统中开发OpenCV
  • 【微机及接口技术】- 第九章 串行通信与串行接口(上)
  • 路由表的最终地址 root 路由跟踪,最终到哪里去
  • RK-realtime Linux
  • python(49)-串口接收与发送
  • Android audio(6)-audiopolicyservice介绍
  • C++Cherno 学习笔记day17 [66]-[70] 类型双关、联合体、虚析构函数、类型转换、条件与操作断点
  • 华为OD全流程解析+备考攻略+经验分享
  • VS Code连接服务器编写Python文件
  • 陕西旱情实探:大型灌区农业供水有保障,大旱之年无旱象
  • 绿景中国地产:洛杉矶酒店出售事项未能及时披露纯属疏忽,已采取补救措施
  • 日本前卫艺术先驱群展上海:当具体派相遇古树古宅
  • AI含量非常高,2025上海教育博览会将于本周五开幕
  • 学者纠错遭网暴,人民锐评:“饭圈”该走出畸形的怪圈了
  • 深入贯彻中央八项规定精神学习教育中央指导组完成进驻