很多人学面向对象设计时都会分别接触到两类东西一类叫设计原则最典型的就是 SOLID一类叫设计模式最典型的就是那 23 种模式但问题也恰恰出在这里。很多人是把这两套东西分开学的学 SOLID 的时候觉得它很重要但太抽象不知道项目里怎么落地学设计模式的时候觉得它像套路但零零散散不知道为什么这样设计到了真实项目里既不会用原则指导设计也不会判断什么时候该上模式结果就是原则背了不少代码还是照旧乱模式看了不少项目里还是不会用一遇到真实业务只能凭感觉写类、写继承、写 if-else这说明一个问题很多人不是不会写代码而是没有把“设计原则”和“设计模式”连起来。而如果你真的想把设计模式用到工程里这件事必须想明白SOLID 是设计的方向设计模式是这些方向在常见场景下的结构化落地。换句话说SOLID 告诉你什么样的设计更健康设计模式告诉你这种健康设计在某些高频问题里通常长什么样这就是它们之间最核心的关系。一、为什么很多人把 SOLID 和设计模式分开学最后反而不会用先说一个很常见的现象。很多人学 SOLID 时会觉得它像这样一套“设计价值观”要单一职责要对扩展开放对修改关闭要依赖抽象不要依赖细节接口不要太大继承要满足语义替换这些说法都对但问题是很多人学完之后仍然不知道具体该怎么拆什么时候抽象抽象完以后类和类怎么组织怎么让“原则”变成真正的代码结构于是另一边他们又去学设计模式。设计模式一般会告诉你策略模式有 Context 和 Strategy状态模式有 State 和 Context工厂方法要有 Creator 和 Product观察者模式有 Subject 和 Observer这些也没错但如果只停在“类图长什么样”就会变成另一种问题知道结构不知道为什么是这个结构知道名字不知道背后解决什么设计矛盾项目里一旦场景稍微变化就不会迁移使用所以问题并不是 SOLID 不够用也不是模式没价值而是原则和模式本来就不该分开理解。你可以把它们理解成这样SOLID 提供判断标准 - 什么样的设计更稳、更可扩展、更少耦合 设计模式提供高频解法 - 当某类问题反复出现时这种结构通常有效也就是说SOLID 更像“设计哲学”设计模式更像“工程经验”如果只学哲学不学经验代码落不下来。如果只学经验不懂哲学模式就会变成死记硬背。二、SOLID 解决的到底是什么问题要理解它和设计模式的关系先得重新看一遍SOLID 到底在解决什么。本系列前面的“类的封装与定义”那篇其实已经讲得很清楚SOLID 的目标不是让代码“看起来高级”而是降低耦合、控制变化传播、提高可维护性。可以把它再压缩成五类问题。2.1 SRP职责为什么总是越写越混单一职责原则说的是一个类应该只有一个引起它变化的原因。它解决的是“一个类承担太多事情”的问题。比如一个类既做协议解析状态维护日志输出网络发送UI 更新那这个类几乎一定会成为耦合中心。一旦变化来了不管改哪件事最后都会落到它身上。SRP 关注的是职责边界。2.2 OCP为什么每次新增功能都在改老代码开闭原则说的是对扩展开放对修改关闭。它不是说旧代码永远不能改而是说稳定部分尽量别被频繁侵入变化部分应该尽量通过扩展接入它解决的是“一有新需求就到处改老逻辑”的问题。2.3 LSP为什么继承以后反而更危险里氏替换原则说的是子类必须能够替换父类并且不破坏程序正确性。它解决的是“继承结构看起来成立但行为语义已经变味”的问题。也就是说继承不是为了代码复用而是为了语义替换。如果子类一接进来调用方就得开始防着它那继承关系通常就不成立。2.4 ISP为什么接口一大所有人都被拖累接口隔离原则说的是不应该强迫客户端依赖它不使用的方法。它解决的是“接口过胖导致实现方和调用方都很痛苦”的问题。很多系统里最大的问题不是没抽象而是抽象得太大、太笼统。2.5 DIP为什么高层逻辑总被底层细节牵着走依赖倒置原则说的是高层模块不应该依赖低层模块二者都应该依赖抽象。它解决的是“业务主流程直接绑死在具体实现上”的问题。比如高层控制流程直接依赖某个具体驱动、某个具体协议、某家供应商 SDK那一旦底层变了高层就会跟着被拖动。而你在“类关系”那篇里强调过依赖关系的方向会直接影响可替换性、可测试性和长期维护成本。三、设计模式解决的又是什么问题理解了 SOLID 之后再来看设计模式会更清楚。设计模式解决的不是“原则对不对”而是当某类设计矛盾反复出现时类和类通常应该怎么组织。换句话说原则描述的是“目标”模式描述的是“高频结构”比如你知道应该对扩展开放这是原则但当你面对“算法会经常增加”这个问题时用策略模式就是一种典型结构化解法再比如你知道应该隔离变化点这是原则但当你面对“状态变化会引起行为变化”时用状态模式就是一种典型组织方式所以模式和原则的关系不是并列的而更像上下层关系原则决定设计方向 - 模式提供常见落地结构再直白一点说SOLID 更像“为什么这么设计”设计模式更像“这种情况下通常怎么设计”四、为什么说“SOLID 是思想设计模式是经验”这是整篇文章最核心的一句话。4.1 SOLID 更像判断标准SOLID 的作用首先是帮你判断当前设计有没有问题。比如你看到一个类职责特别多一个接口又大又胖每次加新功能都改主流程高层逻辑直接依赖底层细节子类到处破坏父类约定你就知道它在违反某些原则。所以 SOLID 更像一个“评估器”这个设计是否容易变化传播这个抽象是否稳定这个依赖方向是否合理这个继承关系是否成立4.2 设计模式更像常见解法模式则更像“处理这些问题的成熟经验”。它不是唯一答案但它是高频答案。比如你发现某一类算法会经常扩展这时策略模式就是常见经验某一类状态会切换且行为跟着状态变这时状态模式就是常见经验创建逻辑复杂且不想让调用方感知细节这时工厂相关模式就是常见经验一个对象变化会通知多个对象这时观察者模式就是常见经验所以可以把二者关系概括为SOLID 告诉你哪里不健康 设计模式告诉你这类问题常见的健康结构是什么4.3 原则决定你为什么这么设计模式决定你可以怎么组织代码这是最值得记住的地方。很多人学习模式时只记住了这个模式有哪些角色这个模式 UML 怎么画这个模式代码长什么样但如果不知道它背后的设计原则就很容易变成机械套用。比如为什么要用策略模式不是因为“有个模式叫策略”而是因为你不想把新增算法写进一堆 if-else你希望新增算法时尽量少改稳定逻辑你希望主流程依赖抽象而不是具体算法你希望每个算法职责清晰、独立测试这些才是它真正背后的原则基础。五、一个个来看常见模式分别在落实哪些 SOLID 原则注意这里不是说“一个模式只对应一条原则”。恰恰相反大多数模式都同时体现多条原则。只是不同模式侧重点不同。5.1 策略模式最典型地落实 OCP 和 DIP策略模式的核心是把一组可替换的算法封装起来调用方依赖统一抽象运行时选择具体策略它最直接体现的是两条原则。第一OCP新增一种策略时不需要改原有主流程只需要新增策略实现即可。也就是说稳定的选择框架尽量不动变化放进扩展点里。第二DIP上下文不依赖具体算法而依赖策略抽象。高层逻辑不会被某个具体实现绑死。第三也能帮助 SRP每个策略类只负责一种算法不需要把多种计算规则堆在一个类里。比如在车企场景里不同车型的能量回收策略不同道路条件下的控制策略不同等级的告警处理策略这些都很容易演化成策略模式。5.2 状态模式把 SRP 和 OCP 落到“状态驱动行为”上状态模式的核心是行为随着状态变化而变化不同状态下的行为拆到不同状态类中Context 持有当前状态并委托处理它首先体现的是 SRP。第一SRP不同状态下的行为不再揉在一个大类里而是分散到不同状态类中。每个状态只负责“这个状态下应该怎么做”。第二OCP新增一个状态通常通过新增状态类完成而不需要把所有分支判断重写一遍。第三某种程度上也体现 DIPContext 依赖的是状态抽象而不是某个具体状态。这和你前面在类设计文章里强调的“有状态的类要明确状态集合、迁移规则和不变量”高度一致。状态模式其实就是当状态复杂到一定程度时把这件事做成一种更稳定的结构。车企里最典型的例子包括整车电源状态机充电状态流转自动泊车流程订单生命周期管理5.3 工厂方法 / 抽象工厂典型地落实 OCP 和 DIP工厂相关模式解决的是“对象创建逻辑”这个问题。它的关键价值不在于“帮你 new 对象”而在于让创建逻辑和使用逻辑分离让高层不直接依赖具体类让对象族扩展更自然第一DIP调用方不应该直接依赖某个具体产品类而应该依赖抽象产品。第二OCP新增一种产品实现时往往通过新增工厂/新增产品族完成而不是到处改调用方。比如车企场景里不同车型平台创建不同的一组控制器对象不同供应商传感器创建不同驱动对象不同协议栈创建不同通信实现如果调用方自己到处 new不仅耦合重而且变化会迅速扩散。5.4 观察者模式把 OCP 和 DIP 用在“通知解耦”上观察者模式的核心是一个对象状态变化多个对象需要接收通知发送方不应该直接依赖具体接收方这里最明显的是两条原则。第一DIP主题依赖观察者抽象而不是依赖一堆具体模块。第二OCP未来要新增一个订阅者通常不需要修改主题核心逻辑只需要新增一个观察者实现并注册。在车企系统里这种场景非常常见车辆状态变化通知 HMI、日志、TBOX、诊断模块充电状态通知多个子系统故障状态广播给多个处理模块如果没有这种抽象系统往往会变成“谁变了就直接去调所有人”耦合会迅速失控。5.5 适配器模式把 OCP 用在接口兼容问题上适配器模式最核心解决的是新接口和老接口不兼容但又不想侵入式修改原有业务流程它最直接体现的是 OCP原有业务逻辑尽量不改新兼容能力通过加一层适配来完成同时它通常也在帮助 DIP业务流程依赖统一抽象接口具体设备/具体协议差异被挡在适配层外在车企项目里这种模式几乎是工程常态新老供应商设备接口不一致CAN、DoIP、串口能力统一接入旧平台能力向新平台过渡5.6 装饰器模式典型体现 OCP 和 SRP装饰器模式解决的是不改原类但要给它叠加新能力它为什么和原则相关第一OCP增强功能时不必改原有类可以通过装饰器扩展。第二SRP不同增强能力可以拆成独立装饰器而不是都堆进基础类。比如在工程里很常见的增强能力日志统计重试限流审计如果这些都直接塞进核心业务类类会越来越臃肿。而装饰器的价值就是把这些横切能力拆开。5.7 模板方法模式常体现 OCP但也提醒你注意 LSP模板方法的核心是父类定义流程骨架子类实现某些可变步骤它确实常常体现 OCP新增一个具体实现时不用改流程骨架通过扩展子类来补充变化点但它也天然会碰到 LSP 风险如果子类过度改写父类语义或者通过覆盖破坏了原有流程假设那么继承关系就会开始变得危险所以模板方法很适合作为一个提醒不是所有“可扩展”都天然安全一旦依赖继承就要格外注意语义替换是否成立。这和你前面“类关系”里对继承的强调是一致的继承不是为了图省事而必须是成立的 is-a 关系。5.8 接口隔离原则最容易体现在哪些模式里很多人谈设计模式时最容易讲 OCP 和 DIP反而忽视 ISP。其实很多模式落地得好不好接口隔离都非常关键。比如策略模式里的策略接口应该只保留真正需要的算法能力观察者模式里的观察者接口应该只包含订阅者真正关心的通知契约命令模式里的命令接口应该聚焦执行语义适配器模式里的目标接口应该足够清晰而不过度膨胀也就是说很多模式并不是天然满足 ISP而是实现这些模式时是否注意接口聚焦决定了它们最终好不好用。六、为什么不能把设计模式机械地等同于 SOLID讲到这里很容易走向另一个极端好像策略模式 OCP DIP状态模式 SRP OCP工厂 OCP DIP观察者 OCP DIP这种理解有帮助但不能太机械。6.1 一个模式通常对应多条原则模式不是“一个模式只落实一条原则”。比如策略模式既体现 OCP也体现 DIP通常还帮助 SRP。状态模式既体现 SRP也体现 OCP同时也依赖合理抽象。装饰器既体现 OCP也常体现 SRP。所以模式和原则不是一对一映射关系。6.2 同一个原则也可能通过多种模式实现比如 OCP不只是策略模式能体现工厂能体现装饰器能体现观察者能体现适配器也能体现也就是说原则是更高层的设计目标而模式只是多种可能实现方式中的高频解法。6.3 模式不是原则的唯一答案你可以在不用任何“标准模式名”的情况下也设计出符合 SOLID 的结构。同样你也可能写出一个“看起来像某种模式”的代码但其实违反了 SOLID。所以真正重要的不是“这是不是某个模式”而是它有没有合理职责边界有没有把变化隔离好依赖方向是否健康抽象是否贴合真实变化点这和你前面文章里反复强调的工程设计思路是一致的不要把原则当教条也不要为了抽象而抽象。七、放到车企场景里怎么理解这件事如果只讲抽象概念容易飘。放回车企场景里这层关系会很清楚。7.1 电源状态机状态模式如何落地 SRP 和 OCP整车电源控制通常有OFFACCONRUNNING甚至还可能有 CHARGING、SLEEP、FAULT 等扩展状态如果把所有状态行为都写进一个大类里最后往往就是一堆switch(state)和各种分支判断。这时候状态模式的价值在于每个状态只负责本状态下的行为体现 SRP新增状态时尽量通过扩展状态类完成体现 OCP这本质上是把你前面类设计文章中强调的“状态集合、迁移规则、不变量”进一步结构化。7.2 诊断通信层DIP 和 ISP 为什么特别重要诊断系统很常见的一种演进路径是先支持 CAN后来要支持 DoIP再后来可能还要支持其他内部总线或仿真链路如果高层诊断流程直接依赖某个具体 transport那一扩展就会侵入主流程。这里通常会引入传输抽象接口高层依赖IDiagnosticTransport具体实现由CanTransport、DoIPTransport等提供这体现的是 DIP。但同时还要注意 ISPTransport 接口只负责传输语义不要把会话控制、安全访问、业务规则混进去否则接口一胖抽象很快就会变味。7.3 不同车型控制策略策略模式如何体现 OCP 和 DIP比如不同车型的能量回收规则不同不同平台的扭矩分配规则不同不同市场法规下的控制策略不同如果把这些差异直接堆进主流程最后主流程就会越来越像一个配置驱动的大分支中心。而策略模式的价值在于主流程依赖统一策略抽象体现 DIP新增策略实现时不必大改主流程体现 OCP7.4 新老供应商接口兼容适配器模式为什么自然出现车企工程里最现实的问题之一就是供应商差异。同样是某类设备或服务A 厂商接口这么定义B 厂商字段、调用顺序、返回语义都不一样但上层业务希望统一使用这时最合理的做法通常不是把所有差异写进业务逻辑而是加一层适配器。适配器并不是为了“套模式”而是因为它正好符合 OCP 的需求老逻辑尽量不动新兼容能力通过适配层扩展进去八、什么时候说明你是在“用原则指导模式”而不是“背模式”这一点特别重要。真正会用模式的人通常不是先想这里能不能套个策略那里能不能搞个状态这块是不是能画成观察者而是先看问题本身。8.1 先看到变化点而不是先想到模式名比如先看到算法会变状态会变通知对象会增加创建逻辑会膨胀接口兼容会越来越多然后再想该不该用成熟模式去承接它。8.2 先知道为什么要抽象而不是为了抽象而抽象抽象不是默认正确只有当它真的隔离了变化点、降低了耦合、提高了可测试性时抽象才有价值。8.3 你能说清这个模式背后到底在保护什么比如策略模式在保护主流程不被算法分支污染状态模式在保护状态规则不被散落工厂在保护使用逻辑不被创建细节绑死观察者在保护通知关系不变成网状耦合8.4 你能说明它对应哪些原则而不只是记住名字这说明你不是“背模式”而是真的理解它。九、总结设计模式和 SOLID 到底是什么关系最简洁的答案是SOLID 回答的是“设计应该朝什么方向做”设计模式回答的是“这些方向在高频场景下通常怎么落地”。它们不是彼此独立的两套知识也不是谁替代谁而是一前一后的关系SOLID 提供判断标准设计模式提供高频解法原则决定为什么这样设计模式决定常见情况下可以怎样组织结构所以真正好的学习路径不应该是先背 5 条原则 再背 23 种模式 最后希望自己自然会用而应该是先理解系统为什么会失控 - 再理解 SOLID 在控制什么问题 - 再理解设计模式如何承接这些问题 - 最后回到真实业务里做取舍如果说你前面的两篇文章讲的是类本身怎么设计类和类之间怎么建立关系那么这一篇讲的就是当这些类开始面对复杂变化时原则和模式如何一起工作一句话收束全文SOLID 是设计的方向感设计模式是工程里的成熟走法真正会设计的人不是只会背原则也不是只会背模式而是能用原则看清问题再用模式组织结构。如果这篇对你有帮助欢迎点赞、转发、关注。我们下一篇继续拆设计模式。