Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

Commit c1d7366

Browse files
职责链模式
1 parent 4fce60c commit c1d7366

6 files changed

Lines changed: 295 additions & 136 deletions

06-设计模式/0 我的总结.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# 我的总结
2+
【未完结】
3+
4+
## 适用场景区别
5+
6+
职责链模式 vs 模板方法模式
7+
职责链目的在于找到合适的处理方法
8+
模板方法模式在于执行一系列方法
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
职责链模式的最大优点就是解耦了 请求发送者 和 N个接收者 之间的复杂关系
2+
由于不知道链中的哪个节点可以处理发出的请求,所以只需把请求传递给第一个节点即可
3+
无论是作用域链、原型链,还是 DOM 节点中的事件冒泡,我们都能从中找到职责链模式的影子
4+
5+
1 对 N 环形关系 ===> 链式关系
6+
7+
<script>
8+
/**
9+
* 【 反面教材 】
10+
* 定金购买:如果支付了500元定金得100优惠券,如果支付了200元定金得50元优惠券,没有成功支付定金的没有优惠券且有库存限制
11+
*/
12+
// 传入用户 订单类型 / 是否支付定金 / 库存
13+
var order = function( orderType, pay, stock ){
14+
// 500 元定金购买模式
15+
if ( orderType === 1 ){
16+
// 已支付定金
17+
if ( pay === true ){ console.log( '500 元定金预购, 得到100 优惠券' ); }
18+
// 未支付定金,降级到普通购买模式
19+
else{
20+
// 用于普通购买的手机还有库存
21+
if ( stock > 0 ){ console.log( '普通购买, 无优惠券' ); }
22+
else{ console.log( '手机库存不足' ); }
23+
}
24+
}
25+
// 200 元定金购买模式
26+
else if ( orderType === 2 ){
27+
if ( pay === true ){ console.log( '200 元定金预购, 得到50 优惠券' ); }
28+
else {
29+
if ( stock > 0 ){ console.log( '普通购买, 无优惠券' ); }
30+
else { console.log( '手机库存不足' ); }
31+
}
32+
}
33+
// 普通模式购买
34+
else if ( orderType === 3 ){
35+
if ( stock > 0 ){ console.log( '普通购买, 无优惠券' ); }
36+
else { console.log( '手机库存不足' ); }
37+
}
38+
};
39+
order( 1 , true, 5 ); // 输出: 500 元定金预购, 得到100 优惠券
40+
41+
/**
42+
* 优化:链式调用,仍然不推荐!!!违反开闭原则
43+
*/
44+
var order500 = function( orderType, pay, stock ){
45+
if ( orderType === 1 && pay === true ){
46+
console.log( '500 元定金预购, 得到100 优惠券' );
47+
}else{
48+
order200( orderType, pay, stock ); // 将请求传递给200 元订单
49+
}
50+
};
51+
// 200 元订单
52+
var order200 = function( orderType, pay, stock ){
53+
if ( orderType === 2 && pay === true ){
54+
console.log( '200 元定金预购, 得到50 优惠券' );
55+
}else{
56+
orderNormal( orderType, pay, stock ); // 将请求传递给普通订单
57+
}
58+
};
59+
// 普通购买订单
60+
var orderNormal = function( orderType, pay, stock ){
61+
if ( stock > 0 ){
62+
console.log( '普通购买, 无优惠券' );
63+
}else{
64+
console.log( '手机库存不足' );
65+
}
66+
};
67+
// 测试结果:
68+
order500( 1 , true, 0); // 输出:500 元定金预购, 得到100 优惠券
69+
order500( 2, true, 0 ); // 输出:200 元定金预购, 得到500 优惠券
70+
order500( 3, false, 1 ); // 输出:普通购买, 无优惠券
71+
order500( 3, false, 0 ); // 输出:手机库存不足
72+
73+
</script>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<script type="text/javascript">
2+
/**
3+
* 定义三类处理节点
4+
* 如果当前节点不能处理,直接返回 nextSuccessor
5+
*/
6+
var order500 = function( orderType, pay, stock ){
7+
if ( orderType === 1 && pay === true ){
8+
console.log( '500 元定金预购,得到100 优惠券' );
9+
}else{
10+
return 'nextSuccessor'; // 不知道下一个节点是谁,反正把请求往后面传递
11+
}
12+
};
13+
var order200 = function( orderType, pay, stock ){
14+
if ( orderType === 2 && pay === true ){
15+
console.log( '200 元定金预购,得到50 优惠券' );
16+
}else{
17+
return 'nextSuccessor'; // 不知道下一个节点是谁,反正把请求往后面传递
18+
}
19+
};
20+
var orderNormal = function( orderType, pay, stock ){
21+
if ( stock > 0 ){
22+
console.log( '普通购买,无优惠券' );
23+
}else{
24+
console.log( '手机库存不足' );
25+
}
26+
};
27+
28+
/**
29+
* 【核心】
30+
* 定义职责链节点,传入节点函数
31+
* 通过 setNextSuccessor 和 passRequest 将节点实例组成链式结构
32+
* 参数 fn 为节点处理函数
33+
*/
34+
var Chain = function( fn ){
35+
this.fn = fn;
36+
this.successor = null;
37+
};
38+
// 指定在链中的下一个节点,参数 successor 为 Chain 节点实例
39+
Chain.prototype.setNextSuccessor = function( successor ){
40+
return this.successor = successor;
41+
};
42+
// 传递请求给某个节点,传入节点处理的参数,节点开始处理
43+
Chain.prototype.passRequest = function(){
44+
// 使用初始化时候传入的 fn 进行处理并取得返回值
45+
var ret = this.fn.apply( this, arguments );
46+
// 如果返回值为 'nextSuccessor' 表示不能处理,传递给下个节点处理
47+
if ( ret === 'nextSuccessor' ) {
48+
// 如果已经 setNextSuccessor 则进行处理
49+
return this.successor && this.successor.passRequest.apply( this.successor, arguments );
50+
}
51+
return ret;
52+
};
53+
54+
/**
55+
* 【 执行 】
56+
* 定义三个节点,传入不同的节点处理函数
57+
*/
58+
var chainOrder500 = new Chain( order500 );
59+
var chainOrder200 = new Chain( order200 );
60+
var chainOrderNormal = new Chain( orderNormal );
61+
// 链式关联,传入上面定义的节点
62+
// chainOrder500.setNextSuccessor( chainOrder200 );
63+
// chainOrder200.setNextSuccessor( chainOrderNormal );
64+
chainOrder500.setNextSuccessor( chainOrder200 ).setNextSuccessor( chainOrderNormal );
65+
66+
// 执行逻辑,起点为 chainOrder500
67+
chainOrder500.passRequest( 1, true, 500 ); // 输出:500 元定金预购,得到 100 优惠券
68+
chainOrder500.passRequest( 2, true, 500 ); // 输出:200 元定金预购,得到 50 优惠券
69+
chainOrder500.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券
70+
chainOrder500.passRequest( 1, false, 0 ); // 输出:手机库存不足
71+
72+
</script>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
前面的 passRequest 用于自动传递同步请求,不能处理异步请求,往往职责链的传递是在异步 ajax 请求结束后才能确定的
2+
本demo额外给职责链添加 next 方法处理异步请求
3+
需要在异步处理函数中主动调用 next 进行下一步
4+
<script>
5+
/**
6+
* 定义职责链,传入节点处理函数
7+
*/
8+
var Chain = function( fn ){
9+
this.fn = fn;
10+
this.successor = null;
11+
};
12+
// setNextSuccessor 指定在链中的下一个节点
13+
Chain.prototype.setNextSuccessor = function( successor ){
14+
return this.successor = successor;
15+
};
16+
// passRequest 传递请求给某个节点
17+
// 通过返回 'nextSuccessor' 自动处理
18+
Chain.prototype.passRequest = function(){
19+
var ret = this.fn.apply( this, arguments );
20+
if ( ret === 'nextSuccessor' ){
21+
return this.successor && this.successor.passRequest.apply( this.successor, arguments );
22+
}
23+
return ret;
24+
};
25+
// next 处理异步职责链
26+
// 动过在异步处理函数中主动调用
27+
Chain.prototype.next= function(){
28+
return this.successor && this.successor.passRequest.apply( this.successor, arguments );
29+
};
30+
31+
/**
32+
* 【执行】
33+
*/
34+
// 节点1,同步处理
35+
var fn1 = new Chain(function(){
36+
console.log( 1 );
37+
return 'nextSuccessor';
38+
});
39+
// 节点2,异步处理
40+
var fn2 = new Chain(function(){
41+
console.log( 2 );
42+
var self = this;
43+
// 1秒后主动调用下个节点处理
44+
setTimeout(function(){
45+
self.next();
46+
}, 1000 );
47+
});
48+
// 节点3,同步处理
49+
var fn3 = new Chain(function(){
50+
console.log( 3 );
51+
});
52+
// 定义链式结构
53+
fn1.setNextSuccessor( fn2 ).setNextSuccessor( fn3 );
54+
// 执行,从节点1开始
55+
fn1.passRequest();
56+
</script>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
利用 JavaScript 的函数式特性,有一种更加方便的方法来创建职责链
2+
用 AOP 来实现职责链既简单又巧妙,但这种把函数叠在一起的方式,同时也叠加了函数的作用域,如果链条太长的话,也会对性能有较大的影响
3+
4+
【 OOP 与 AOP 的区别 】
5+
面向目标不同:OOP 面向名词领域,AOP 面向动词领域
6+
思想结构不同:OOP 是纵向结构,AOP 是横向结构
7+
注重方面不同:OOP 注重业务逻辑单元的划分,AOP 偏重业务处理过程中的某个步骤或阶段
8+
【 OOP 与 AOP 的联系 】
9+
两者之间是一个相互补充和完善的关系
10+
11+
<script type="text/javascript">
12+
/**
13+
* 定义三类处理节点
14+
* 如果当前节点不能处理,直接返回 nextSuccessor
15+
*/
16+
var order500 = function( orderType, pay, stock ){
17+
if ( orderType === 1 && pay === true ){
18+
console.log( '500 元定金预购,得到100 优惠券' );
19+
}else{
20+
return 'nextSuccessor'; // 不知道下一个节点是谁,反正把请求往后面传递
21+
}
22+
};
23+
var order200 = function( orderType, pay, stock ){
24+
if ( orderType === 2 && pay === true ){
25+
console.log( '200 元定金预购,得到50 优惠券' );
26+
}else{
27+
return 'nextSuccessor'; // 不知道下一个节点是谁,反正把请求往后面传递
28+
}
29+
};
30+
var orderNormal = function( orderType, pay, stock ){
31+
if ( stock > 0 ){
32+
console.log( '普通购买,无优惠券' );
33+
}else{
34+
console.log( '手机库存不足' );
35+
}
36+
};
37+
38+
/**
39+
* 【核心】
40+
* AOP,为 Function 添加 after 方法
41+
* 每个函数都拥有了 after 方法
42+
* 传入下个节点处理函数
43+
*/
44+
Function.prototype.after = function( fn ){
45+
var self = this;
46+
return function() {
47+
// 调用各自处理函数的after方法时先执行了当前函数
48+
// AREA1: 如 order500.after(order200) 先执行了 order500()
49+
var ret = self.apply( this, arguments );
50+
// 再根据返回结果,确定要不要继续执行
51+
// 如果返回 'nextSuccessor',则传递给下个节点函数处理
52+
if ( ret === 'nextSuccessor' ) {
53+
// AREA2: 执行下个节点
54+
return fn.apply( this, arguments );
55+
}
56+
// 否则返回结果值
57+
return ret;
58+
}
59+
};
60+
61+
// 函数式编程,确定链式关系,规定 order500 的下个节点为 order200,order 的下个节点为 orderNormal
62+
/*
63+
分析:
64+
order500.after( order200 ) 返回的是一个函数,并未执行
65+
order500.after( order200 ).after( orderNormal ) 因为上面返回值是一个函数,因此有after方法,再次返回一个函数,未执行
66+
形成函数链
67+
*/
68+
var order = order500.after( order200 ).after( orderNormal );
69+
70+
/**
71+
* 【注意】
72+
* 确定链式关系时候执行完全流程
73+
*/
74+
/*
75+
分析:
76+
先执行了 AREA1: order500( 2, true, 5 ),返回结果:ret = 'nextSuccessor'
77+
执行下个节点 AREA2: order200( 2, true, 5 ),返回结果:ret = undefined
78+
// TODO
79+
*/
80+
// order( 1, true, 5 ); // 输出:500 元定金预购,得到100 优惠券
81+
order( 2, true, 5 ); // 输出:200 元定金预购,得到50 优惠券
82+
// order( 1, false, 5 ); // 输出:普通购买,无优惠券
83+
84+
</script>

0 commit comments

Comments
 (0)