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 模板方法都分步骤建造者是对象构建,
模板方法是算法流程