使用策略模式封装拦截器
通过if-else 来实现拦截器的封装
axios.interceptors.response.use((res) => { let {message, statusCode} = res.data.data // 退出登录状态码 let logoutCodes = new Set([435001, 435011, 436050]) if (statusCode === 1000) { // 更新全局token let {pragma} = res.headers if (pragma) window.token = pragma // 返回数据 return res.data.data } else if (logoutCodes.has(statusCode)) { setTimeout(() => window.logout(), 1000) return Promise.reject({message}) } else { return Promise.reject({message,statusCode}) } }, (error) => { return Promise.reject(error.response.data) })
首先,说一下上面拦截器封装的逻辑,当状态码为1000的时候,请求数据成功,当状态码为435001, 435011, 436050的时候,退出登录。其他状态码的时候,返回错误信息。 在最开始封装拦截器的时候,使用了大量的if-else的。在可读性上是不太 友好的,而且,后期的维护也不是很友好。 最近,正好在学习设计模式,感觉这个可以通过策略模式来进行优化.
策略模式就是将一系列的算法单独封装起来,并且他们可以相互替换。策略模式有两个类:一是策略类,二是环境类。策略类封装了具体的算法,并负责具体的计算过程。环境类是接收客户端的请求,随后把请求委托给某一个策略类。
第一次使用策略模式进行的封装
// 定义策略类 let Policy = { // 状态码满足1000的情况下 success: function(res) { let {pragma} = res.headers; pragma && (window.token = pragma); // 返回数据 return res.data.result }, // 状态码满足435001,435011, 436050情况下,登出 logout: function(res) { let {message} = res.data; setTimeout(() => window.logout(), 1000) return Promise.reject({message}) }, // 状态码满足其他情况下 other: function() { let {message, statusCode} = res.data return Promise.reject({message,statusCode}) } } /** * 响应拦截器 * @author liuqiuyue * @date 2019-04-29 */ axios.interceptors.response.use((res) => { let {statusCode} = res.data // 退出登录状态码 let logoutCodes = new Set([435001, 435011, 436050]) let codeBol = (statusCode === 1000); let logoutBol = (logoutCodes.has(statusCode)); // 满足状态码为1000的时候,执行的方法 codeBol && Policy.success(res); // 状态码满足435001,435011, 436050情况下,登出 !codeBol && logoutBol && Policy.logout(res); // 状态码满足其他情况下 !codeBol && !logoutBol && Policy.other(res); }, (error) => { return Promise.reject(error.response.data) })
封装了一个对象,这个对象里面含有不同的方法,在满足条件的时候,去走不同策略类中的方法。看似是策略模式,我也一直这么认为,这是符合策略模式的。之前也经常认为中写法是符合策略模式的。经高人指点之后,发现,这其实不算一个真正的策略模式,可以说是一个伪策略模式。为什么这么说呢? 推荐阅读 https://www.runoob.com/?s=%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8
上面的代码 中Policy是对一系列的算法进行了封装,但是会发现,其实是没有环境类的,只是通过不同的条件,去调取不同的方法的。所以,他是伪策略模式。
对策略模式进行二次封装 通过一个加减乘除的算法的案例来解释
策略类
function computed() { } computed.prototype.add = function(a, b) { console.log('走了嘛') return a+b } computed.prototype.subtraction = function(a, b) { return a-b } computed.prototype.Multiply = function(a,b) { return a*b } computed.prototype.except = function(a, b) { return a/b }
环境类
// 定义了环境类 function context() { } context.prototype.init= function(a, b) { this.a =a; this.b = b; console.log('数值初始化', this.a, this.b) } context.prototype.getWay = function(way) { console.log('way', way) return way(this.a, this.b) }
客户端的请求,具体的实现
var c = new context() c.init(10, 20) let com = new computed(); c.getWay(com.add) console.log('结果', c.getWay(com.add))
在解释这种说法之前,先说一下面向对象的概念,
(1)类,有相同的特征和行为的事物的抽象,
( 2)对象 :类的一个实例。
那么。js是面向对象语言嘛?
准确点说,js是一种基于面向对象的语言,因为,她没有提供抽象,继承,重载等有关面向对象语言的许多功能,而是把其他语言所创建的复杂对象统一起来,从而形成一个非常强大的对象系统,这种独特性称它为prototype_basedOO(基于原型的面向对象)。传统的是class-basedOO(基于类的面向对象)
上面的这种写法就是使用的js的基于原型的面向对象去实现的策略模式。
下面,通过传统的基于类的面向对象思想进行封装
Strategy抽象类
export class Strategy { // 抽象类 constructor() { } init(num1, num2) { console.log('抽象类', num1, num2) this.num1 = num1; this.num2 =num2; } }
Add方法,继承于Strategy类
import {Strategy} from '../js/Strategy' export class Add extends Strategy{ constructor(num1, num2) { super(num1, num2) } init(num1, num2) { console.log('数据', num1, num2) return num1+num2 } }
Context环境类
// 环境类 let {Strategy} = require('../js/Strategy') let strategy = new Strategy() export class Context { constructor() { this.strategy =strategy } // 定义抽象类的方式 initWay(way) { // 数据的初始化 this.strategy = way console.log('数据的初始化', this.strategy) } // 计算 getWay(num1, num2) { console.log('获取对应的方法', num1, num2) console.log('结果', this.strategy.init(num1, num2)) return this.strategy.init(num1, num2) } }
实现
var contenx = new Context() context.getWay(add)