策略模式Strategy Pattern是 C 中经典的行为型设计模式。它的核心思想是定义一组算法将每个算法封装起来并使它们可以互相替换从而让算法的变化独立于使用算法的客户。在 C 中我们可以利用虚函数、模板、std::function甚至编译期多态等多种方式实现比 Java 更加灵活。1. 现实场景类比假设你正在编写一个图像压缩工具支持多种压缩算法JPEG、PNG、WebP用户选择“JPEG” → 调用 JPEG 压缩逻辑用户选择“PNG” → 调用 PNG 压缩逻辑用户选择“WebP” → 调用 WebP 压缩逻辑“压缩图像”这个目标是固定的但“具体怎么压缩”是可变的。策略模式将这些算法封装成独立的策略让用户随时切换而不用写一堆if-else。2. 解决的问题何时使用如果你在 C 项目中看到类似代码if(formatJPEG){// 50行 JPEG 压缩逻辑}elseif(formatPNG){// 50行 PNG 压缩逻辑}elseif(formatWebP){// 50行 WebP 压缩逻辑}这就是策略模式的最佳使用场景。它的存在避免了违反开闭原则新增算法必须修改原有类。类职责过重一个类里塞满了各种算法变体。测试困难算法逻辑耦合在一起难以单独测试。3. C 中的经典结构三要素角色作用抽象策略定义一个接口纯虚类声明所有策略必须实现的成员函数。具体策略实现抽象策略接口封装具体的算法。上下文持有一个策略指针或引用通过它调用策略方法。客户端与上下文交互。标准代码骨架面向对象方式#includeiostream#includememory// 1. 抽象策略接口classCompressionStrategy{public:virtual~CompressionStrategy()default;virtualvoidcompress(conststd::stringfile)const0;};// 2. 具体策略AclassJPEGCompression:publicCompressionStrategy{public:voidcompress(conststd::stringfile)constoverride{std::cout使用 JPEG 算法压缩 filestd::endl;}};// 3. 具体策略BclassPNGCompression:publicCompressionStrategy{public:voidcompress(conststd::stringfile)constoverride{std::cout使用 PNG 算法压缩 filestd::endl;}};// 4. 上下文classCompressor{private:std::unique_ptrCompressionStrategystrategy_;// 使用智能指针管理public:explicitCompressor(std::unique_ptrCompressionStrategystrategy):strategy_(std::move(strategy)){}voidsetStrategy(std::unique_ptrCompressionStrategystrategy){strategy_std::move(strategy);}voidcompressFile(conststd::stringfile)const{if(strategy_){strategy_-compress(file);}}};// 客户端使用intmain(){autocompressorCompressor(std::make_uniqueJPEGCompression());compressor.compressFile(photo.jpg);// JPEGcompressor.setStrategy(std::make_uniquePNGCompression());compressor.compressFile(photo.png);// PNG}4. C 现代方式函数式策略更灵活C11 引入了std::function和 lambda我们可以将策略表示为可调用对象完全不需要定义类代码简洁得惊人。#includefunctional#includeiostream#includestringusingCompressionStrategystd::functionvoid(conststd::string);classCompressor{private:CompressionStrategy strategy_;public:explicitCompressor(CompressionStrategy strategy):strategy_(std::move(strategy)){}voidsetStrategy(CompressionStrategy strategy){strategy_std::move(strategy);}voidcompressFile(conststd::stringfile)const{if(strategy_){strategy_(file);}}};intmain(){// 直接使用 lambda 作为策略Compressorcompressor([](conststd::stringfile){std::coutJPEG压缩filestd::endl;});compressor.compressFile(photo.jpg);// 运行时切换策略compressor.setStrategy([](conststd::stringfile){std::coutPNG压缩filestd::endl;});compressor.compressFile(photo.png);}这种方式避免了类的继承树特别适合算法逻辑简单且无需维护内部状态的场景。5. C 独有编译期多态模板策略如果策略在编译期就能确定我们可以利用模板实现零运行时开销的策略模式。这在性能敏感场景如游戏、嵌入式中非常常用。#includeiostream// 具体策略不继承任何基类structJPEGCompression{voidcompress(conststd::stringfile)const{std::coutJPEG压缩filestd::endl;}};structPNGCompression{voidcompress(conststd::stringfile)const{std::coutPNG压缩filestd::endl;}};// 上下文模板templatetypenameStrategyclassCompressor{private:Strategy strategy_;public:explicitCompressor(Strategy strategyStrategy{}):strategy_(std::move(strategy)){}voidcompressFile(conststd::stringfile)const{strategy_.compress(file);}};intmain(){CompressorJPEGCompressionjpegCompressor;jpegCompressor.compressFile(photo.jpg);CompressorPNGCompressionpngCompressor;pngCompressor.compressFile(photo.png);}模板版本的策略模式没有虚函数开销所有调用在编译期绑定性能最佳。缺点是无法在运行时动态切换策略。6. 策略模式在 C 生态中的经典应用STL 容器排序std::sort接受一个比较器函数对象这就是策略模式的典型应用。智能指针删除器std::unique_ptr的删除器可以自定义用于不同的内存释放策略。网络库不同的序列化格式JSON、ProtoBuf、XML可以封装为不同策略。图形渲染引擎不同的渲染后端OpenGL、Vulkan、DirectX作为独立策略。7. 优缺点C 视角优点缺点解耦算法定义与使用分离符合单一职责原则。类数量膨胀面向对象方式每个策略一个类但可用std::function缓解。完美支持开闭原则新增策略无需修改原有代码。模板策略在运行时无法切换编译期绑定灵活性受限。消除冗长条件分支代码更清晰、可维护性更高。策略间可能无法共享状态如果需要共享上下文数据需通过参数传递或上下文持有。支持多种实现风格虚函数、std::function、模板任选适应不同场景。-8. 如何选择实现方式场景推荐方式策略需要在运行时动态切换如用户选择算法虚函数 继承或std::function策略在编译期已知且追求极致性能如高频调用模板 静态多态策略逻辑简单且无需维护内部状态std::function lambda最简洁策略内部状态复杂需要封装成员变量虚函数 继承更自然地管理状态总结在 C 中策略模式的精髓是“将算法从业务逻辑中抽离”而 C 提供了比 Java、Python 更丰富的实现手段传统 OOP 方式保证了运行时灵活性std::function让代码轻量化模板多态则在性能关键路径上大放异彩。如果你正在重构一个满是if-else的 C 项目策略模式是最值得优先考虑的重构工具。选择最适合你场景的实现风格就能让代码在可维护性与性能之间达到最佳平衡。