1. 设计原则
1.1 何为设计
1.1.1 设计的描述
描述
- 即
按照哪一种思路或者标准来实现功能
功能相同
,可以有不同设计方案
来实现
- 伴随着
需求增加
,设计的作用才能体现出来
1.1.2 设计准则
小即是美
让每个程序只做好一件事
- 把各个子程序都
分开
,让每个子程序都做好一件事情
- 每个子程序都足够的小,每一个大程序都是小程序的
集合
,一个相互传感
的关系
快速建立原型
- 先把原型搭建起来,先满足用户
最基本的需求
- 用户反馈问题后,再去
升级
- 升级
新增功能或新需求、修复反馈问题
舍弃高效率而取可移植性
- 如果一个程序
执行效率很高
,但是就一个地方能够使用,别的地方都不能用
- 但是另一个程序虽然
执行效率不高
,但是可以移植、拷贝、复用
- 那我们会选择后者
- 因为
高效率
相对于代码的可移植性
来说,优先级要低很多
- 例如,一个组件、插件、SDK等等程序写出来,只是高效,而不能通用
- 那在别的地方仍然要重新写程序
- 一个成熟的产品写出来是很费劲的
- 要经过编写、测试、用户长时间的使用经验积累等等,十分费劲
- 所以程序首先保证的就是
可移植性
- 对于高效的问题,可以依赖
硬件升级
- 例如,今年产品的代码可能有点低效,但是会被硬件的升级而磨平
- 过几年,硬件升级,像摄像头、屏幕、CPU、内存等等配置升级后,软件程序自然就提高运行效率了
采用纯文本来存储数据
- 在
效率
和可读性
上的取舍
- 纯文本便利人
阅读分析
- 如果存储二进制,那人基本看不懂
- 但是对于计算机而言,二进制显然更好,
存储的空间更小、存储效率更高、程序间不用格式转换
- 但是我们还是更倾向于
可读性
,二进制转码可以利用效率的方式去弥补
充分利用软件的杠杆效应(软件复用)
使用 shell 脚本来提高杠杆效应和可移植性
避免强制性的用户界面
- 我们用惯了Windows、安卓、Word、Excel等一些系统的图形化界面
- 但是Linux和Unix的服务器端或者纯正的产品,都是没有图形化界面的,没有鼠标拖拽、画图等等
- 只有命令行
- 用户界面应该
以一个单独的软件存在,而不是一个系统的必备项
- 因为如果用户界面存在于服务器端的话,会导致很多问题
- 比如,
占用内存、用户界面的输入会引起安全性问题
- 用户界面的交互和系统的交互,入口会更多,会带来安全性的问题
- 而命令行交互比较简单,可以
限制一些复杂交互,从而避免一些安全问题
- 用户界面也没有命令行那么高效
- 所以
系统应该和用户界面是分开的,不要强制去绑定用户界面
让每个程序都成为过滤器
- 可以把数据先到A程序里处理,出来结果之后再到B程序里处理,然后出来结果之后再到C程序中处理
1.1.3 设计小准则
允许用户定制环境
尽量使操作系统内核小而轻量化
内核要小,轻量化
- 包含
最核心的API
- 其他需要使用的东西可以通过
插件扩展
的方式来增加
使用小写字母并尽量简短
沉默是金
- 输出一个数,必须是数字,如果不是一个数字
- 就输出0或者什么都不输出
各部分之和大于整体
- 以多个小体组成一个大体
- 如果需要修改,小体不会影响其他小体
寻求 90% 的解决方案
- 产品面向用户的时候,只需要保证90%的用户
- 根本不可能满足100%的用户需求
1.2 七大设计原则
1.2.1 S – 单一职责原则
Single Responsibility Principle, SRP
- 一个程序只做好一件事
如果功能过于复杂就拆分开,每个部分保持独立
- 设计系统的时候,每个部分要保持独立
- 各个部分是
相互关联、相互利用
的关系
1.2.2 O – 开放封闭原则
Open-Closed Principle, OCP
对扩展开发,对修改封闭
增加需求时,扩展新代码,而非修改已有代码
- 所有的系统、网页、app都需要增加需求,要求尽量扩展新代码,而非修改已有代码
- 如果每次增加需求的时候,都修改已有代码,不是扩展新代码,会带来一些问题
- 修改已有代码,需要测试,要将系统重新回归一遍,
成本高,对整个开发流程及测试人员一个很大的压力
- 多人开发的情况,扩展新代码造成冲突很小,如果修改已有代码,很
容易造成冲突
1.2.3 L – 里氏置换原则
Liskov Substitution Principle, LSP
子类能覆盖父类
- 父类能出现的地方子类就能出现
- JS中使用较少(弱类型 & 继承使用较少)
1.2.4 I – 接口独立原则
Interface Segregation Principle, ISP
保持接口的单一独立,避免出现 "胖接口"
- 写接口、函数、定义API的时候尽量分开,单个是单个,保持独立,尽量不要出现一个接口或函数把所有事都揽过来的情况
- JS中没有接口(TypeScript例外),使用较少
- 类似于单一职责原则,这里更关注接口
1.2.5 D – 依赖倒置原则
Dependence Inversion Principle, DIP
面向接口编程,依赖于抽象而不依赖于具体
- 使用方只关注接口而不关注具体类的实现
- JS中使用较少(没有接口 & 弱类型)
1.2.6 迪米特原则
Law of Demeter, LoD
- 一个对象应当对其他对象有尽可能少的了解
降低各个对象之间的耦合,提高系统的可维护性
1.2.7 合成复用原则
Composite Reuse Principle, CRP
- 尽量使用
对象组合
,而不是继承
来达到复用的目的
继承关系是强耦合,组合关系是低耦合
1.3 设计原则实例
function loadImg(src) {
var promise = new Promise(function (resolve, reject) {
var img = document.createElement('img')
img.onload = function () {
resolve(img)
}
img.onerror = function () {
reject('图片加载失败')
}
img.src = src
})
return promise
}
var src = 'https://www.imooc.com/static/img/index/logo_new.png'
var result = loadImg(src)
result.then(function(img) {
console.log('img.width', img.width)
return img
}).then(function(img) {
console.log('img.height', img.height)
}).catch(function(ex) {
console.log(ex)
})