职责链模式

什么是职责链模式?

  职责链模式的定义是解耦请求的发送者和请求的接受者,所有的对象都有机会执行,直到有对象处理请求为止。

  职责链的作用是让业务代码更具可维护性和可拓展性。

什么时候使用职责链?

例如:

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

原文地址:https://www.cnblogs.com/yy95/p/9932421.html