【Javascript設計模式】責任鍊模式

使多個對像都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係,將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象能處理它為止,傳遞鏈中的這些對象就叫節點。

在實際的運用當中,責任鍊模式也常常用在重構繁瑣的if… if else… 中,這和之前學習的策略模式有相似之處,相比策略,責任鍊模式邏輯上更加繁瑣,但是責任鍊模式有著更大的彈性空間。
假如上一個環節的結果,是需要交給下一個環節來繼續加工,那麼此時責任鍊模式是更加適合處理的。
接下來假設一個需求

一個電商網站,
用戶交500定金且定金已付時,可享受500優惠券且不受貨物數量限制;
用戶交200定金且定金已付時,可享受500優惠券且不受貨物數量限制;
用戶不交定金時受貨物數量限制,有貨時原價買,無貨時則無法買。

var buyOrder = function(orederType, pay, stock){
	if(orederType == 1){
		if(pay){
          console.log('500优惠券');
        } else {
          if(stock > 0){
            console.log('普通购物页面');
          } else {
            console.log('已无货');
          }
        }
      } else if(orederType == 2){
        if(pay){
          console.log('200优惠券');
        } else {
          if(stock > 0){
            console.log('普通购物页面');
          } else {
            console.log('已无货');
          }
        }
      } else if(orederType == 3){
        if(stock > 0){
          console.log('普通购物页面');
        } else {
          console.log('已无货');
        }
      }
}
buyOrder(1, true, 600)

接下來調用它

//3个订单函数 ,它们都是节点函数
const order500 = function (orderType, pay, stock) {
	if (orderType == '1' && pay == true) {
      console.log('500优惠券');
    } else {
      return 'nextSuccessor';     // 不管下一個節點是誰,反正就是把請求往後傳遞
   }
}
const order200 = function (orderType, pay, stock) {
	if (orderType == '2' && pay == true) {
		console.log('200优惠券');
	} else {
        return 'nextSuccessor';     // 不管下一個節點是誰,反正就是把請求往後傳遞
    }
}
const orderNormal = function (orderType, pay, stock) {
	if (stock > 0) {
    	console.log('普通购物页面');
	} else {
        console.log('已无货');
    }
}
//把3個訂單函數分別包裝成職責鏈的節點
const chainOrder500 = new Chain(order500)
const chainOrder200 = new Chain(order200)
const chainOrderNormal = new Chain(orderNormal)

//然後指定節點在職責鏈中的順序
chainOrder500.setNextSuccessor(chainOrder200)
chainOrder200.setNextSuccessor(chainOrderNormal)

//最後把請求傳遞給第一個節點,開啟職責鏈模式傳遞
chainOrder500.handleRequest(1, true, 500)     //500优惠券
chainOrder500.handleRequest(3, true, 20)      //普通购物页面
chainOrder500.handleRequest(3, true, 0)       //已无货

之後來分享一下另外一個例子:
有一個活動的H5頁面,頁面被用在多個瀏覽器環境,比如微信、QQ、自己開發的app、其他第三方的app等等等等。由於後台接口對不同環境登錄態的處理不同,需要判斷不同環境,取cookie裡面的不同值,傳不同的登錄態token,有時候還要針對某些特殊環境,對網絡請求有一些特殊處理。

以下為typescript的例子,可以看到BaseHandler 這個類別是抽象類,表示它必須的依附在另外一個實例當中

  // 请求拦截器责任链节点抽象类
export default abstract class BaseHandler {
	// 下一个节点
    private nextHandler: BaseHandler | null = null;
    // 设置下一个节点
    public setNextHandler (handler: BaseHandler): BaseHandler {
       this.nextHandler = handler;
       return this.nextHandler;
    }
	// 调用该节点的方法处理请求,处理后,调用下一节点继续处理
    public handleRequest (config: any): void {
       // 当前节点的处理
       if (this.checkHandler(config)) {
           this.handler(config);
       }
       // 继续执行下一个节点
       if (this.nextHandler) {
           this.nextHandler.handlerRequest(config);
		}
	}
	// 调用该节点的方法处理请求,有一个节点处理就直接退出(互斥的)
  public handleRequestOnce(config: any): void {
    // 当前节点的处理
    if (this.checkHandle(config)) {
      this.handler(config);
    } else if (this.nextHandler) {
      this.nextHandler.handleRequestOnce(config);
    }
  }

  // 判断是否在这个节点处理
  abstract checkHandle(config: any): boolean;
  // 处理的方式
  abstract handler(config: any): void;
}
/*

作者:lucio来全学了
链接:https://juejin.cn/post/7055149674650402824
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
import BaseHandler from '../../base-handler';
import { getUrlPara } from '../../../url';
import { env } from '../../../env';

// 处理小程序内嵌H5的请求参数
export default class WechatMpParamsHandler extends BaseHandler {
  // 在王者人生小程序,且为QQ登录,才用小程序登录态,其他情况下都用微信登录态
  checkHandle(): boolean {
    return env.isMiniProgram;
  }
  handler(config: any): any {
    if (getUrlPara('_ticket')) {
      config.params._ticket = getUrlPara('_ticket');
    }
    return config;
  }
}
/*
作者:lucio来全学了
链接:https://juejin.cn/post/7055149674650402824
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处
*/

最後在axios攔截器實現調用

// 请求拦截器
const requestInterceptor =  function (config) {
  const requestHandlerChain = new UrlInterceptor(); // 请求的责任链节点:CGI的URL处理
  requestHandlerChain.setNextHandler(new ParamsInterceptor()); // 请求的责任链节点:CGI的参数处理
  requestHandlerChain.handleRequest(config);
  return config;
};

// 响应拦截器
const responseInterceptor = (response) => {
  const responseHandlerChain = new ParseDataInterceptor(); // 返回数据的责任链节点:解析新老框架的数据
  responseHandlerChain.setNextHandler(new LoginInfoInterceptor()) // 返回数据的责任链节点:处理登录信息
    .setNextHandler(new ErrorToastInterceptor()); // 返回数据的责任链节点:处理错误提示
  responseHandlerChain.handleRequest(response);
  return response;
};

// 请求拦截器
axiosInstance.interceptors.request.use(requestInterceptor, error => Promise.reject(error));

// 响应拦截器
axiosInstance.interceptors.response.use(responseInterceptor, error => Promise.reject(error));
/*
作者:lucio来全学了
链接:https://juejin.cn/post/7055149674650402824
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/

以上待續…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值