9.七大原则总结

9.总结


9.1 知识点

七大原则会一直伴随开发生涯,要尽量遵循。做客户端或 Unity 项目时,玩法迭代、SDK 换皮、多平台分支最容易把类糊成一团,这几条原则多半用在这类「收拾耦合」的场景里。


9.2 核心要点速览

七大原则怎么记

  • SOLID:前五条原则的英文名首字母凑成 S、O、L、I、D,资料和书里提到 SOLID 一般就指这五项。
  • CD:本系列把组合复用迪米特接在 SOLID 后面记;口诀里常念「稳固的 CD」,C 是 Composite Reuse,D 是 Demeter。
中文名 英文全称
单一职责原则 Single Responsibility Principle
开放封闭原则 Open-Closed Principle
里氏替换原则 Liskov Substitution Principle
接口隔离原则 Interface Segregation Principle
依赖倒转原则 Dependency Inversion Principle
组合复用原则 Composite Reuse Principle
迪米特法则 Law of Demeter
  • 中英文名称记熟,看文档、对需求、Code Review 时对得上号;原则之间会打架,落地时按项目阶段和改动频率做取舍,但方向尽量别偏太远。

单一职责原则

  • 定义:一个类只该有一个修改的理由——不是机械数方法个数,而是「一类变更别总打在同一坨代码上」。
  • 实操信号:单类体积暴涨时先怀疑职责是否糊在一起;原文拿 500 行当粗告警,用来触发排查可以,别当成铁律。

开放封闭原则

  • 定义:类、模块、函数对扩展开放、对修改关闭:新需求优先用新类型、新实现接进去,少动已经跑过版本、踩过坑的老逻辑。
  • 对照简单工厂加产品常常要改工厂里的分支;工厂方法多半是多加一个工厂子类和一个产品类,对旧工厂的改动面更小。

里氏替换原则

  • 定义:凡是能用父类或接口引用正常工作的地方,换成子类实例,语义和正确性不能掉链子。
  • 多态写法:声明类型用父类或接口,运行时塞子类对象。空接口、空父类只为把引用类型统一成一种的写法项目里能见到,读代码的人通常要多想一步。

接口隔离原则

  • 定义:别逼一个类去实现它根本用不到的接口成员。
  • 落地:接口宁可多拆几个、每个口子小一点,也别搞一个「啥都管」的大接口,末尾跟一排空方法或永远不调的实现,后面谁也不敢动。

依赖倒转原则

  • 定义:高层别直接依赖低层的具体类,两边都对着抽象编程;抽象不跟着某个 SDK 细节跑,细节去实现抽象。
  • 典型场景:接渠道 SDK、接安卓/iOS 原生能力时,游戏逻辑层只拿桥接接口或平台抽象;具体平台实现放在适配层注入,避免在玩法代码里写满平台分支和具体类型。

组合复用原则

  • 定义:复用代码时优先组合(持有引用、组装能力),少用继承把几条独立的变化轴绑成一张大网。
  • 数量直觉10 品牌 × 10 软件,若每种组合做一个子类,类数往 100 走;拆成手机抽象 + 软件接口,用组合关联,一般是 10 + 10 量级。和桥接里「两个维度别用继承相乘」是同一类问题。

迪米特法则

  • 定义:也叫最少知道:只跟直接朋友交互,别为了拿一点数据把整条对象图都摸一遍。
  • 目的:依赖面收窄,改内部实现时,外围业务类少跟着重编译、少跟着改调用。

9.3 面试题精选

基础题

1. 单一职责原则里「只有一个修改理由」怎么理解

题目

口头解释 SRP 时,别停在「一个类只做一件事」六个字。

深入解析
  • 正文抓的是修改理由:职责一杂,某个玩法或系统一改,Git 冲突和回归范围容易全堆在一个大类上。
  • 行数只是闹钟:500 行提醒你去看来龙去脉;真要拆不拆,看变更是不是总从同一个类开刀
答题示例

单一职责我按「修改理由」记:最好一类需求变动,主要动到的那块代码就一处。

职责糊在一起,小需求也改同一个大类,合并冲突和测试面都大;类特别长会提醒我去看是不是职责没切开,但不会只看行数下刀。

参考文章
  • 2.单一职责原则

2. 开放封闭原则两句话怎么说清

题目

用两三句话说明开放、封闭各指什么。

深入解析
  • 扩展开放:新玩法、新渠道、新配置,尽量用新类、新模块接进现有骨架,而不是把老模块掏心掏肺重写。
  • 修改关闭:线上跑过、QA 踩过的主干逻辑,能不动就不动,改动面小,版本风险才可控。
答题示例

扩展开放:加东西优先靠加类型、加实现,把新行为挂到稳定扩展点上。

修改关闭:已经验证过的核心流程少动刀,避免每个版本都在老代码里做大手术。

参考文章
  • 3.开放封闭原则

3. 里氏替换原则关心的是什么

题目

「子类能替换父类」到底替换的是类型位置还是对象身份?

深入解析
  • 替换的是声明类型能出现的位置:变量、参数、返回值写成基类或接口时,实际对象可以是子类,调用方按父类契约写代码仍然成立
  • 子类如果在父类默认能成功的路径上多失败、少保证,等于换了实现却换了契约,和多态的前提矛盾;这类追问通常挂在 LSP 下面。
答题示例

里氏替换关心的是:父类引用能用的场合,塞子类对象,行为语义不能坏。

写法就是接口或父类声明、子类实现。子类在父类默认可走通的路径上突然失败或收紧前提,就已经偏了可替换性。

参考文章
  • 4.里氏替换原则

4. 接口隔离原则主要解决什么问题

题目

ISP 和「接口方法少一点」是不是一回事?

深入解析
  • 重点是别强迫实现类签它用不到的契约;方法多只是胖接口的外在样子。
  • 后果常见是一排空方法、假实现,或者 C# 里随手 throw new NotImplementedException(),接口变成摆设,重构时谁也不敢动。
答题示例

接口隔离解决的是:类不该去实现自己用不到的接口成员。

方法多往往是表象,实质是实现类在凑接口,留一堆空实现或假实现,后面删也不敢删、改也不敢改。

参考文章
  • 5.接口隔离原则

进阶题

1. 简单工厂和工厂方法,哪个更贴开放封闭

题目

结合系列里的例子说明:加新产品时两类工厂各要动哪里。

深入解析
  • 简单工厂:一个工厂类里用分支或表决定 new 谁,新产品往往要改这段集中逻辑
  • 工厂方法:每种产品配自己的工厂子类,扩展主要是加类,对既有工厂类的改动通常更小。
答题示例

简单工厂加产品,经常要动工厂里挑类型的那段代码;工厂方法多是加工厂子类加产品类,老工厂文件可以少碰。

从 OCP 倾向看工厂方法更顺一点,代价是类型变多,项目里要认这个取舍。

参考文章
  • 3.开放封闭原则

2. 依赖倒转在跨平台桥接里怎么落地

题目

结合正文里的安卓/苹果桥接,说明玩法层该依赖什么类型。

深入解析
  • 玩法或框架上层只拿桥接抽象(接口或抽象类),具体安卓、iOS 实现放在适配层或插件里
  • 换 SDK、加渠道时,动刀范围压在适配实现上,主干逻辑文件尽量不动。
答题示例

玩法代码不要直接依赖安卓桥接类、苹果桥接类两种具体类型,而是依赖桥接接口,平台侧各自实现再注入。

上新平台就加一份实现,调用点仍然面向接口,测试和回归主要围着适配层转。

参考文章
  • 6.依赖倒转原则

3. 组合复用原则用数量举例想说明什么

题目

10 品牌 × 10 软件,继承方案和组合方案类数量差在哪、背后是什么维度问题。

深入解析
  • 两个独立变化轴用继承拧在一起,子类个数按笛卡尔积涨,维护成本跟着指数感往上顶。
  • 组合做法是把两条轴拆开:一侧类型树 + 另一侧接口,用引用连起来,类数量大致跟各轴实现个数同阶。
答题示例

继承把两个维度绑死,10×10 会冲到接近一百个类;手机抽象加软件接口做组合,一般是十个加十个这种量级。

正文想说的是别用继承去乘独立变化维度,桥接就是把两条轴拆开连。

参考文章
  • 7.组合复用原则

深度题

1. 子类在父类能成功的路径上额外失败,和哪条原则冲突

题目

子类重写后多抛异常、或父类默认能成功的路径在子类里变失败,和哪条原则冲突。

深入解析
  • 落在 LSP:能替换不只是编译器不报错,而是调用方按父类约定写好的逻辑仍然成立
  • 正文写的是「替换而不影响正确性」:业务结果、异常、返回值、前置条件都算契约的一部分;子类放大失败面或收窄成功面,多态调用方就会莫名其妙炸。
答题示例

这是里氏替换被打破了:调用方按父类约定写,子类却在同样输入下更容易失败或结果不一致。

子类可以比父类更强,但不能在父类默认可用的路径上突然多出一种父类没声明的失败方式;返回值、异常、前置条件要和父类契约对齐。

参考文章
  • 4.里氏替换原则

2. 迪米特法则和「点号链式调用」有什么关系

题目

业务类里写 a.getB().getC().doThing() 常被挑刺,用正文里的「最少知道」怎么接。

深入解析
  • 正文强调少知道远处对象:一长串 getter 等于业务类摸清了 B、C 的内部拼图,直接朋友以外的东西也变成了依赖。
  • B、C 内部一调整,业务类每一行点号都可能要改;法则希望依赖停在更近的一层。
答题示例

迪米特要的是最少知道:别为了办一件事把中间对象的形状全摊在调用方。

点号链把 B、C 的结构细节绑进业务类,内部一改上层跟着改。更稳的是在中间层或门面包一层「做完这件事」的方法,业务只打一次调用。

参考文章
  • 8.迪米特法则

3. 组合复用是否等于禁止继承

题目

系列强调优先组合,继承还能用在哪。

深入解析
  • 正文说的是优先组合,不是把继承从语言里抠掉;类型关系稳定、确实是 is-a,或用模板方法抽骨架,继承仍然顺手。
  • 组合更利于运行时换实现(策略、桥接、接平台),继承把关系钉死在类层次上;轴选错了,扩展和单测隔离都会别扭。
答题示例

不是不用继承,而是别用继承把几条独立变化轴乘成一片子类海,维护成本顶不住。

类型层次清楚、算法骨架复用,继承照样用;要换 SDK、换策略、拆平台这类频繁变的,组合或桥接更省事。

参考文章
  • 7.组合复用原则


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏