1. 设计原则
1.1. 通用原则
1.1.1. KISS原则(keep it sample and stupid)
- 懒人原则
- 注重简约的原则, 逻辑处理上应该用简单直接的设计.
- 圈复杂度越小越好, if for case while的数量.
如非必要, 请远离各种设计模式
1.2. 核心原则
1.2.1. 单一职责原则(SRP)
做一个专一的人
不能存在多于一个导致类变更的原因, 一个类之负责一项职责.
迭代器的实现, 集合只负责存储数据, 迭代器完成遍历数据的功能
1.2.2. 开放封闭原则 (OCP)
改造世界的大部分不能破坏原来的秩序
软件实体应该是可扩展, 不可修改的. 对扩展开放, 对修改封闭
新的修改不要大幅度波及现有的对象
小技巧: 使用继承/组合封装变化点,
将变化点封装出一个抽象基类, 使用继承机制, 让子类演绎变化
1.2.3. 里氏替换原则 (LSP)
长大后, 我就成了你
任何积累可以出现的地方, 子类一定可以出现.
子类不破坏父类的接口成员
当基类出现了子类不想要的接口成员时, 继承关系欠缺考虑, 违反LSP原则
1.2.4. 接口分离原则 (ISP)
不要一口吃成胖子
不能强迫用户去依赖那些不使用的接口, 使用多个专门的接口比使用单一的总接口要好
1.2.5. 依赖倒置原则 (DIP)
抽象的艺术才有生命力
- 高层模块不应依赖底层模块, 两者都应依赖于抽象
- 抽象不应依赖细节
- 细节(具体实现类)依赖抽象
1.2.6. 核心原则小结
类要单纯, 继承要纯粹, 变化要封装, 抽象类型要多用
1.3. 扩展规则
1.3.1. 狄米特法则
尽量不与无关的类发生关系
最少知识原则: 你调用的类的内部是如何实现的, 与我无关. 我只知道你提供的接口方法, 其他的一概不关心.
通俗点的说法:
- 只与你的朋友说话
- 不要与陌生人说话
- 对象因该只与必须交互的对象通信
技术上的说法, 对象只与下类必须交互的各类对象进行通信:
- 当前对象本身(this)
- 以参数形式传入当前方法中的对象
- 当前对象的成员对象 (this的成员变量)
- 如果成员对象是一个集合, 集合中的元素也是可以交互的
- 当前对象创建的对象
1.3.2. 好莱坞法则
不要调用我, 让我调用你
多使用回调的方式.
1.3.3. 优先使用组合
多使用组合, 少使用继承.
继承使用的场景:
满足严格的IS-A关系, 即子类可以完全复用基类的所有信息时, 继承是必须的
要么有冗余关系, 要么复用程度不够时, 不推荐完全使用继承关系.
1.4. 应对变化
1.4.1. 增量修改原则
开闭原则, 尽量不修改原有的类和方法, 通过新增类和方法实现.
1.4.2. 整体策略原则
设计整体上考虑变化,而不仅仅考虑变化点周围的小区域
1.4.3. 应对变化的设计思路
预先设计
程序设计时就把可能存在的变化考虑到, 在程序上预留一定的扩展性
采用抽象类型来描述稳定的接口, 使用子类和多态机制来描述变化.简单设计+封装变化
很多时候, 变化总是不期而至,无法做到预先设计,当变化来的时候, 通过封装变化点来重构程序
1.5. 设计的四个阶段
1.5.1. 设计不足
- 没有系统的观念, 代码写到哪想到哪,想到哪写到哪.
- 代码随意堆彻, 各种编程元素随意使用, 元素可见性\生命周期使用混乱
- 元素随意命名, 数字随意使用
- 代码随意复制和粘贴, 功能相似的函数不考虑复用
- 代码无法应对需求变化, 维护成本很高
1.5.2. 模仿设计
- 开始考虑程序对系统其他方面的影响, 开始考虑设计
- 开始应用简单的模式
- 开始学习一些好的写法, 并学会整理自己的代码
1.5.3. 过度设计
- 见到全局的概念就使用单例模式
- 需要通知就使用观察者模式
- 见到稍微复杂一点的对象创建就使用抽象工厂模式
- 见到算法变化了一点就使用策略模式
- 见到软件就分三层
- 见到变化就抽象
- 见到依赖就注入
- 任何行为都想抽象接口
- 任何设计都考虑是否具有通用扩展性
过度设计是在软件设计过程中实施了不必要的通用的扩展性设计, 增加了不必要的面向未来的设计, 进行了不必要的抽象封装.
适度设计
合时宜, 恰如其分,有时间制约, 合适的时间成本, 恰当的对接需求.