什么是职责链模式?
职责链模式的定义是解耦请求的发送者和请求的接受者,所有的对象都有机会执行,直到有对象处理请求为止。
职责链的作用是让业务代码更具可维护性和可拓展性。
什么时候使用职责链?
例如:
1、给一个未知的元素里面添加一个按钮,并且给这个按钮添加一个点击事件
2、电商平台的优惠券:交满500元定金,得100优惠券;交满200元定金,50优惠券;没交定金的,按普通用户算,没有优惠券。
等等...
需求多变的时候,需要考虑适应多种情况,可以考虑职责链是否可以封装业务代码。
怎么用职责链模式实现上面第二个需求?
考虑到未来可能会有新的类型,比如交满300元定金,得60元优惠券,然后不要交满200元定金这个需求,如何编写代码来更好的适配我们多变的需求?
let order500 = function( orderType, pay, stock ){
if ( orderType === 1 && pay === true ){
console.log( '500 元定金预购,得到100 优惠券' );
}else{
return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递,解耦
}
};
let order200 = function( orderType, pay, stock ){
if ( orderType === 2 && pay === true ){
console.log( '200 元定金预购,得到50 优惠券' );
}else{
return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递
}
};
let orderNormal = function( orderType, pay, stock ){
if ( stock > 0 ){
console.log( '普通购买,无优惠券' );
}else{
console.log( '手机库存不足' );
}
};
let Chain = function( fn ){
this.fn = fn;
this.successor = null;
};
Chain.prototype.setNextSuccessor = function( successor ){
return this.successor = successor;
};
Chain.prototype.passRequest = function(){
let ret = this.fn.apply( this, arguments );//从执行chainOrder500开始,如果满足条件就会停止往下执行
if ( ret === 'nextSuccessor' ){//如果执行chainOrder500没有满足条件就会返回nextSuccessor,执行下个函数
return this.successor && this.successor.passRequest.apply( this.successor, arguments );
}
return ret;
};
//创建对象-节点
let chainOrder500 = new Chain( order500 );
let chainOrder200 = new Chain( order200 );
let chainOrderNormal = new Chain( orderNormal );
//将对象(节点)串成链
chainOrder500.setNextSuccessor( chainOrder200 );
chainOrder200.setNextSuccessor( chainOrderNormal );
//执行测试
chainOrder500.passRequest( 1, true, 500 ); // 输出:500 元定金预购,得到100 优惠券
chainOrder500.passRequest( 2, true, 500 ); // 输出:200 元定金预购,得到50 优惠券
chainOrder500.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券
chainOrder500.passRequest( 1, false, 0 ); // 输出:手机库存不足
项目中的实际场景:
多种类型的复制链接的操作,也可以将业务代码用职责链来封装
1、

copyLink() {
const result = copyMethods({
content: this.qr
})
if(result){
this.$message.success('复制图片url成功!')
} else {
this.$message.error('复制失败')
}
},
2、

copy(content, e){
const el = e.target.parentNode.querySelector('.piece-content')
const result = copyMethods({ content, el })
if(result){
this.$message.success('成功复制文本')
} else {
this.$message.error('复制失败')
}
},
具体实现:
function copyWithRange({ el }){
if(!el || !document.createRange) return 'next'
let range = document.createRange()
range.selectNode(el)
window.getSelection().addRange(range)
const result = document.execCommand('copy')
window.getSelection().removeAllRanges()
return result
}
function copyWithClipEvent({ content }){
function copy (e) {
// content = `<${content}/>`
e.clipboardData.setData('text/plain', content)
e.preventDefault()
}
// 添加 copy 内容
document.addEventListener('copy',copy)
// 执行 copy 命令
const result = document.execCommand('copy')
// 移除绑定事件
document.removeEventListener('copy',copy)
return result
}
function copyWithInput({ content }){
let aux = document.createElement('input')
aux.setAttribute('value', content)
document.body.appendChild(aux)
aux.select()
window.getSelection().toString()
const result = document.execCommand('copy')
document.body.removeChild(aux)
return result
}
//职责链封装三个快捷复制的操作
function copyMethods({ content, el }){
const fns = [
copyWithRange,
copyWithClipEvent,
copyWithInput,
]
const fnChains = chain(fns)
return fnChains({ content, el })
}
function after(fn, afterFn){
return function(...args){
const result = fn.apply(this, args)
if(result === 'next'){
return afterFn.apply(this, args)
}
return result
}
}
function chain(fns){
return fns.reduce((pre, next) => {
return after(pre, next)
})
}
参考资料:
https://zhuanlan.zhihu.com/p/28327127
https://www.cnblogs.com/xiaohuochai/p/8040195.html

浙公网安备 33010602011771号