单一职责原则
一个方法负责一项职责,只能有一项引起函数变化的原因
当一个函数用来处理多个事件时,我们需要对其进行分离,便于增加函数的可读性,方便对函数进行扩充。例如:当我们异步加载图片时
function loadImg() ({
let img = new Image()
document.body.append(img)
return function(imgNode) {
img.src = imgNode
}
})()
function ProxyImg() (function() {
let img = new Image()
img.onload = function() {
loadImg(this.src)
}
return function(imgNode) {
img.src = imgNode
loadImg('占位图片')
}
})()
proxyImg('https://ww.example.com/1.jpg')
通过单一职责原则,我们把异步加载图片和设置图片的职能分开,就算以后不用异步加载图片了,直接把 proxyImg
换成 loadImg
就行了,不用再更改函数
单一职责原则也有一些缺点,最明显的就是增加了代码复杂度,也增加了对象之间的联系难度
最少知识原则
一个对象应该对其他对象保持最少的了解
最少知识原则要求我们尽量减少两个对象之间的交互,这时候可以引入一个”第三者“,
比如说中介者模式,当多个对象需要交互时,我们引入一个中介者,用来处理逻辑,防止各个对象之间进行交互。例如:当我们进行多人对战游戏时,当剩余一半玩家时,则剩余玩家获得胜利:
当用户死亡时,如直接交互,可能需要向其余对象各发布一次死亡信息,其他对象需要自身对其他用户状况进行保存,这样进一步增加了代码的复杂度 当我们引入一个中介者来处理事件逻辑时:class User {
constructor(name) {
this.name = name
this.state = 'alive'
}
die() {
this.state = 'dead'
userAgent.lose()
}
win() {
console.log(this.name + '胜利')
}
lose() {
console.log(this.name + '失败')
}
}
function userFactory(name) {
let user = new User(name)
userAgent.add(user)
return user
}
// 中介,用来处理中间逻辑
userAgent = (function() {
let players = []
function add(user) {
players.push(user)
}
function lose() {
let deadNum = 0
for (let i = 0; i < players.length; i++) {
if (players[i].state === 'dead') {
deadNum += 1
}
}
if (deadNum >= Math.round(players.length / 2)) {
players.forEach(user => {
if (user.state === 'dead') {
user.lose()
}
else {
user.win()
}
})
}
}
return {
add,
lose
}
})()
let user1 = userFactory('111')
let user2 = userFactory('222')
let user3 = userFactory('333')
let user4 = userFactory('444')
user3.die()
user2.die()
// 111胜利
// 222失败
// 333失败
// 444胜利
遵守最少知识原则可以减少不必要的交互,降低各个函数之间的耦合性
但是遵守最少知识原则缺点也很明显:会增加代码的复杂度。在示例中,我们为了避免直接交互,引入了一个”中介“,导致代码复杂度增加,因此,使用时应该权衡利弊。
开放闭合原则
当需要改变程序功能时,可以通过对其进行扩展,但是不允许改变原函数
当我们为旧代码中的函数添加新功能时,直接更改函数往往会引起不必要的错误,开放闭合原则让我们不用更改源码,而是在函数上进行二次扩展,常用形式比如说函数 AOP 插槽,通过放置 hook 来进行扩展
例如:常用的对函数原型链进行 before
after
扩展
Function.prototype.before = function(fn) {
let self = this
return function() {
fn.apply(this, arguments)
return self.apply(this, arguments)
}
}
Function.prototype.after = function(fn) {
let self = this
return function() {
let ret = self.apply(this, arguments)
fn.apply(this, arguments)
return ret
}
}
function test() {
console.log('test')
}
var test = test
.before(function() {
console.log('before')
})
.after(function() {
console.log('after')
})
test()
// before
// test
// after
扩展的函数不会改变原函数的执行结果,还可以共享 arguments
基本上 JavaScript 中常用的设计模式都遵守 开放-封闭原则