preface
The chain of responsibility pattern is very common in our development, but for those of you who don’t know, you may have implemented similar logic in the if/else way before. The chain of responsibility mainly refers to the process of chain judgment when the implementation of a specific thing is uncertain about which logic to use until the function or object that meets the conditions is found and then processed. Analysis, found that in fact, the logic behind a lot of our code is the responsibility chain pattern.
The illustration
The chain of responsibility in reality
In reality, there are many examples. For example, when we are crowded in a bus, if there are too many people, we pass coins through people and pass them forward until the person in front is the driver or conductor. This is a very obvious example of responsibility chain.
Code refactoring
The original code was basically doing constant judgments with if and else, doing different logic.
Case description
Before the refactoring
const order = (orderType,pay,stock){
if(orderType === 1) {if(pay === true) {console.log('500 yuan deposit, 100 coupons returned ')}else {
if(stock > 0 ){
consle.log('Regular purchase, no coupons')}else {
console.log('Understock')}}}else if(orderType === 2) {if(pay === true) {console.log('200 yuan deposit, 50 coupons returned ')}else {
if(stock > 0 ){
consle.log('Regular purchase, no coupons')}else {
console.log('Understock')}}}else{
if(stock > 0 ){
consle.log('Regular purchase, no coupons')}else {
console.log('Understock')}}}Copy the code
After the reconstruction
In accordance with the design idea of responsibility chain, we have reached the position in one step, including the following ideas:
- Encapsulate the different purchase patterns as functions
- Implementation of chain function, can continue to add functions, can be inconsistent, implementation of submission
const order500 = function(orderType,pay,stock){
if(orderType === 1 && pay === true) {console.log('500 yuan deposit, 100 coupons returned ')}else {
return 'nextSuccessor'; }}const order200 = function(orderType,pay,stock){
if(orderType === 2 && pay === true) {console.log('200 yuan deposit, 50 coupons returned ')}else {
return 'nextSuccessor'; }}const orderNormal = function(orderType,pay,stock){
if(stock > 0) {console.log('Regular purchase, no coupons')}else {
console.log('Understock')}}const 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);
if(ret === '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.false.0);
chainOrder500.passRequest(1.true.10);
chainOrder500.passRequest(2.true.11);
chainOrder500.passRequest(2.false.1);
Copy the code
Codepen address: codepen. IO /robinson90/…
Responsibilities driven Design and the practice of state patterns
The article links: mp.weixin.qq.com/s/qQEEnf79F…
demand
The solution
The responsibility driven concept is introduced to judge which object has the ability of operation from the perspective of knowledge ability.
However, the disadvantage of this is that when new states are added, all the state classes of the implementation interface need to be changed, which does not conform to the open and closed principle of design pattern.
State diagram:
Another kind of chain of responsibility
This is not in the typical chain of responsibility design. It is my own opinion in the development process, which also conforms to the formal chain judgment, but ultimately only determines the execution of a final function, rather than the implementation of chain delivery.
Of course, it may not belong to any design pattern at all, but I think the essence of a design pattern is to solve the fixed mindset of a fixed scene, and the name is not the point.
The specific code is as follows:
let Chain = function(){
let dutyArr = []
this.addDuty = function(duty){
dutyArr.push(duty)
}
this.opt = function(params){
for(let index in dutyArr){
if(dutyArr[index].judge(params)){
returndutyArr[index].opt && dutyArr[index].opt(params); }}return false}}let ageChainDemo = new Chain();
ageChainDemo.addDuty({
judge:function(params){
let {age} = params;
return age > 18;
},
opt:function(params){
let {age} = params;
return 'You're an adult now.'
}
})
ageChainDemo.addDuty({
judge:function(params){
let {age} = params;
return age > 0 && age < 18;
},
opt:function(params){
let {age} = params;
return 'You're a minor.'}})let result = ageChainDemo.opt({age:20});
console.log(result);
let result2 =ageChainDemo.opt({age:10});
console.log(result2);
Copy the code
Codepen address: codepen. IO /robinson90/…
Differences from the policy pattern
At first glance, the chain of responsibility is written as nothing like the policy pattern, which maintains separate functional logic, with the main difference being the judgment of the use condition.
The policy pattern can determine exactly which policy to use and determine which strategy to use to return results; In the chain of responsibility mode, the use of conditions is abstracted and built into the function. Through continuous internal judgment of the function, if the function does not meet the requirements, the judgment needs to continue to pass until the function that meets the requirements is executed and executed.
From this, we can decide that if we are vague about the conditions, we are better off using the chain of responsibility. This is better than writing complex Booleans inside if/else, or using the result value of a computed variable, or using the return result of another function.
More and more
The original link: www.yuque.com/robinson/de…
More learning and understanding of the design patterns, can walk into my design pattern album: www.yuque.com/robinson/de…