-
Notifications
You must be signed in to change notification settings - Fork 0
Description
掌握策略模式对于培养大家的良好的编程习惯和重构意识大有裨益.
下面来看看策略模式的定义:
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
策略模式目的:
策略模式的目的就是将算法的使用与算法的实现分离开来.
抛开概念, 来看一个真实场景问题.
支付方式
有一天产品经理牛哥找小明说,我们需要接入几种支付方式分别对应:
- 支付宝
- 京东
- 微信
小明思索了一下, 心里并有了实现方式. 便找后端拿到对应支付方式标识对应如下:
支付宝: 1701
京东: 1702
微信: 1703
接着仔细读完接入文档,进入相应的开发. 大概的实现如下:
const alipayId = 1701;
const jdpayId = 1702;
const wechatId = 1703;
function toPay(params){
if(alipayId === params.payType) {
console.log("调用支付宝")
}else if(jdpayId === params.payType) {
console.log("调用京东")
}else if(wechatId === params.payType) {
console.log("调用微信")
}else {
console.log("未找到对应支付方式")
}
}
这基本上能满足我们的功能层面的要求, 但是这种实现有没有问题 ?
- 违法单一原则,所有支付方式的实现都放在一起,随着版本迭代代码体积也会是非常的庞大且难以维护.
- 复用性差,其它地方需要复用其中一些支付方法,显然现在写法不能满足的.
- 缺乏弹性,假设又新增一种买鸭支付方式,需要深入到
toPay
内部,这同样违反了开发封闭原则
.
问题多不可怕,重点去改善它.
使用组合函数来重构代码
把每个支付方式的实现进行提取(extract), 如下.
function aliPay(){
console.log("调用支付宝")
}
function jdPay(){
console.log("调用京东")
}
function wechatPay(){
console.log("调用微信")
}
function toPay(params){
if(alipayId === params.payType) {
aliPay();
}else if(jdpayId === params.payType) {
jdPay();
}else if(wechatId === params.payType) {
wechatPay();
}else {
console.log("未找到对应支付方式")
}
}
OK, 现在每个函数都只负责一件事,同时支付方式的复用性得到提高.
虽然经过上面的改造后在一定程度上改善了我们代码,但是依然没有解决最重要的问题: toPay
函数体积可能会越来越大的问题, 而且当系统发生变化的时候缺乏弹性.
先来捋一捋 toPay
做的事情, 主要接收用户请求,将请求分发给不同支付方式并执行.
在第一步改造主要围绕着执行
阶段, 那么剩下的就要从 分发
入手.
开放封闭改造
由于业务的需求,现在需要添加一种新的支付方式买鸭
分期, 小明想了想我这么做就好了,如下:
function aliPay(){
console.log("调用支付宝")
}
function jdPay(){
console.log("调用京东")
}
function wechatPay(){
console.log("调用微信")
}
function maiyaPay(){
console.log("调用买鸭")
}
function toPay(params){
if(alipayId === params.payType) {
aliPay();
}else if(jdpayId === params.payType) {
jdPay();
}else if(wechatId === params.payType) {
wechatPay();
}else if(maiyaId === params.payType) {
maiyaPay();
}else {
console.log("未找到对应支付方式")
}
}
上面是新增 maiyaPay
方法,然后在 toPay
中添加 if-else
分支,这应该是大家常用的解决方案. 这样其实还是在修改 toPay
的函数体, 没有实现对扩展开放、对修改封闭
的效果.
那我该怎么做? 其实仔细想一想, toPay
中 if-else
作用就是把支付方式与处理函数进行匹配. 那么在JS中有没有既能明确映射他们之间的关系,又不损失其灵活性的方法? 对象映射
现在我们通过对象方式来改进它.
首先把所有支付方式收集到一个对象中:
const alipayId = 1701;
const jdpayId = 1702;
const wechatId = 1703;
const maiyaId = 1704;
const strategies = {
[alipayId]: (){
console.log("调用支付宝")
},
[jdpayId]: (){
console.log("调用京东")
},
[wechatId]: (){
console.log("调用微信")
},
[maiyaId]: (){
console.log("调用买鸭")
},
}
当我们使用某个支付方式的时,可以通过支付方式 payType
去获取即可:
function toPay(params){
const payMethod = strategies[params.payType];
payMethod(params)
}
这样一来, if-else
被消除了, 同样后面新增支付方式,我们只需要在 strategies
中新增即可.
现在回顾前面的定义 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
. 算法可以理解就是每种支付方式处理函数. 概念里面的“相互替换”指的是“多态”. 这里可以不用去关心.
接着看看策略模式的目的将算法的使用与算法的实现分离开来. 再仔细回顾我们实现是不是就是这样的.
任何场景下遇到类似问题, 那么应该想一想有没有更好的实现方式, 不要只用 if-else
一把梭了.