JavaScript 设计模式----设计原则

1. 设计原则

1.1 何为设计

  • 推荐书籍
    • UNIX/LINUX 设计哲学
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)
})
  • 单一职责原则体现
    • 每个 then 中的逻辑只做好一件事
  • 开放封闭原则体现
    • 如果有新增需求,扩展 then 即可

猜你喜欢

转载自blog.csdn.net/qq_43645678/article/details/113959796