sum - 设计原则 · 设计模式
关闭原则: 对拓展开放, 对修改关闭
比如搜狗输入法的皮肤是输入法的背景图片、窗口颜色和声音的等元素的组合, 用户按需求更换皮肤, 我们就把皮肤抽象为一个接口, 然后每一个具体的皮肤就是他的子实现类, 不用每次创建皮肤都得重新皮肤类, 而是用接口来接收它
里氏代换: 基类出现的地方, 子类一定能出现
父类的代码, 换成子类对象后, 功能和逻辑应该保持一致
- 子类可以拓展父类的功能, 但不能改变父类原来的功能
- 子类要保持父类行为的一致性
- IO、异常、状态变化符合父类的约定
- 不能随意重写父类的方法
- 如果子类行为 与 父类完全不同, 最好不要继承
- 可以考虑 组合(has) 代替 继承(is)
- 子类要保持父类行为的一致性
总结
- LSP是为了保证继承层次的可替换性
- 重写父类方法可能破坏祖宗之法
- 若子类不能合理实现父类行为, 继承可能不是最好的设计
例子
- 比如鸡和鸟, 鸡不会飞, 就别继承鸟---->将飞写成接口
- 比如矩形和正方形, 矩形能设置不同长宽, 正方形却不能, 因此将长宽写作接口
依赖倒转: 高层次不依赖低层次
高层次和低层次都应该依赖抽象 ( 接口 / 抽象类 ) 抽象不应该依赖细节, 细节应该依赖抽象
你写业务逻辑(高层模块)的时候,不要直接去 new 一个具体实现(低层模块),而是依赖接口。
DIP = 设计原则 → “依赖接口而不是实现
接口隔离: 一个类不要依赖不使用的接口
*客户端不能被迫依赖于他不使用的方法, 一个类不能依赖于他不使用的接口, 大的接口应该拆分成多个更小、更专一的接口 *
迪米特: 不要和陌生人说话
对象之间的通信应该尽量松散:
- 一个类只和直接关联的累 (成员变量、方法参数、返回值) 打交道
- 不应该通过一层层的传话来访问别的对象
如明星通过经纪人去商业洽谈/粉丝见面等
合成复用: 尽量用组合/聚合, 避免继承/实现
- 继承会带来强耦合:父类改动可能影响所有子类;
- 组合/聚合关系更灵活:可以在运行时动态替换组件;
- 面向接口编程 + 依赖倒转原则,可以让“组合”更优雅地实现。
一些横纵向的对比
创建型
| 模式 | 核心思想 | 关键/对比 |
|---|---|---|
| 单例 | 全局唯一实例 | 饿汉 / 懒汉 / enum |
| 原型 | 克隆已有对象 | 浅克隆 vs 深克隆 |
| 工厂方法 | 子类决定创建 | vs 抽象工厂 |
| 抽象工厂 | 提供一族相关对象 | vs 工厂方法, 多个产品等级 |
| 建造者 | 分步骤构建复杂对象 | vs 模板方法, 顺序可控 |
结构型
| 模式 | 核心思想 | 关键 / 对比 |
|---|---|---|
| 适配器 | 接口转换 | 类适配器 vs 对象适配器 |
| 桥接 | 多维度解耦 | 功能维度和实现维度分离 |
| 装饰者 | 动态扩展对象 | vs 代理: 增强 vs 控制访问 |
| 外观 | 简化复杂接口 | vs 桥接: 桥接是解耦, 外观是简化 |
| 享元 | 共享对象减少开销 | 内外部状态分离, Integer缓存 |
| 组合 | 树形结构, 统一操作 | vs 装饰器: 组合强调 “部分-整体” 装饰强调 “增强” |
| 代理 | 控制访问 | 静态 vs 动态代理, JDK vs CGLIB |
对比记忆: “装饰 vs 代理” : 都是持有原对象, 区别在 “增强功能 vs 控制访问” “外观 vs 桥接” : 外观是简化调用, 桥接是解耦实现
行为型
| 模式 | 核心 | 关键 / 对比 |
|---|---|---|
| 模板方法 | 固定流程 + 可重写步骤 | 钩子函数, 反向控制 |
| 策略 | 算法可替换 | 接口 + 多态, Context 持有策略对象 |
| 命令 | 封装请求 | client -> command -> executor, 可做撤销 / 排队 |
| 观察者 | 发布订阅 | 一对多通知, Listen模式 |
| 责任链 | 多级处理 | 动态链式传递请求, Handler链 |
| 状态 | 状态切换改变行为 | Context + 状态对象, 电梯例子 |
| 访问者 | 数据结构+操作分离 | 双分派: 对象 + 操作运行时决定 |
| 中介者 | 统一通信 | 避免对象直接引用, 简化耦合 |
| 备忘录 | 保存和恢复对象状态 | Editor+History, 黑箱vs白箱 |
| 解释器 | DSL / 规则解释 | 树形结构+解析器 |
| 双分派/动态代理 | 方法调用根据两种类型分派 | JDK Proxy实现AOP基础 |
对比记忆
- 状态 vs 策略 : 状态对象内部管理切换, 策略外部由Context持有
- 观察者 vs 中介者 : 观察者是广播, 中介者是集中协调
- 命令 vs 策略 : 命令封装动作 + 接收者, 策略封装算法
易混淆对比
| 模式 | 易混淆点 | 区别记忆法 |
|---|---|---|
| 装饰 vs 代理 | 都持有原对象 | 装饰增强功能, 代理控制访问 |
| 桥接 vs 适配器 | 都解耦 | 桥接是提前设计的多维度, 适配器是后加接口兼容 |
| 观察者 vs 中介者 | 都通知 | 观察者是一对多, 外部广播 中介者是中间协调, 减少直接依赖 |
| 状态 vs 策略 | 都用多态 | 状态关注对象行为随状态的变化, 策略关注算法替换 |
| 建造者 vs 模板方法 | 都分步骤 | 建造者是对象构建, 模板方法是算法流程 |