行为型模式之策略模式

[TOC]

前言

在讲解策略模式之前,我们了解下行为型设计模式。那么行为型是什么意思呢?主要场景是什么呢?

行为型设计模式主要是用于不同对象之间职责划分或者算法抽象,行为型设计模式不仅仅涉及类和对象,还涉及类或者对象之间的交流模式并加以实现。

感谢作者张容铭对本模式的讲解,非常透彻清晰,我只是一个搬运工,做好自己的学习实践,谨记:他山之石,可以攻玉。

策略模式

策略模式是把一系列的算法封装起来,让其可以相互替换,封装的算法具有一定的独立性,不随客户端的变化而变化。

场景应用

马上到圣诞节了,老板要让你做一款活动的促销活动,根据用户不同等级给与不同的返现。然后你就开始下面这样写了

function return30(price){

}

function return50(price){

}

然后开始了switch

我相信不少人都会这样写,没什么问题,能工作,看上去维护性也很好。

但好像你忘掉了什么,这只是一堆零散的代码啊,我还需要做的是:
1 如何把不同的打折返现模式封装起来
2 如何根据不同情况去使用我想要的,很明显目前的方式是不行的,因为目前的函数是暴露在全局的。如果我另外的位置需要还需要写这么一堆switch语句。

switch(user.cheaperLevel){
    case return30 :  return30(price);
    break;
    case return60 :  return60(price);
    break;
}

价格策略对象

const PriceStrategy = function(){
// 内部算法对象
    const stragtegy = {
       return30:function(price){
        },
       return60:function(price){
        },
    }
// 策略算法调用接口
   return function(cheaperLevel,price){
       return stragtegy[cheaperLevel] && stragtegy[cheaperLevel](price)
   }
}

// 使用方式
let price = PriceStrategy('return30','321.56')
console.log(price)

小结:这样实现之后,我们在使用时只要关注如何调用而不用关注原来的算法;而负责算法的人也可以统筹所有的算法策略,通过策略的api暴露的方式提供给使用者。

jq延伸拓展

jq中的策略模式使用案例,相信你一定使用jq的animate的动画函数。

其调用过程是这样的:

$("div").animate({width:300px},1000,'linear')
$("div").animate({width:300px},1000,'swing')

通过一个关键字我们就可以调用其内部封装的30种动画,而不用关心其内部实现。

追本溯源,我们定位到jq的源码:

// line 660-667 https://github.com/jquery/jquery/blob/2.0.0/src/effects.js
jQuery.easing = {
    linear: function( p ) {
        return p;
    },
    swing: function( p ) {
        return 0.5 - Math.cos( p*Math.PI ) / 2;
    }
};

表单验证

除了上面的,其实我们工作中复杂常用的表单验证也可以用这个设计模式轻松实现,甚至我们还可以根据自己的需要去为其增加策略。

const inputStrategy = () => {
    const strategy = {
        notNull : (val) => {
            return /\s+/.test(val) ? '请输入' : '';
        },
        number :(val) => {
            return val.isNaN ? '请输入数字' :'';
        }
    }
    return {
        check:(type,value)=>{
           return  strategy[type](value) ;
        },
        // 肯定策略不够用,为它添加一个自定义的策略Api
        addStrategy:(type,fn)=>{
            strategy[type] = fn ;
        }
    }
}

// 算法调用
let inputValue = document.getElmentById('target');
let isVaild = inputStrategy.check('number',inputValue);

总结

虽然好像说的很明白了,但好像你觉得并没有和开始的分支语句有什么区别,那么我把区别重点说明下。

  • 将算法单独维护在策略对象里,负责算法的人不用关心具体业务使用;而业务方只要负责调用即可;
  • 通过对算法的封装实现了对算法的引用,避免了重复;
  • 策略模式也是分支语句的一种优化技巧,目的也是为了让其更加可维护。如果你觉得你的分支语句上升不到策略的高度完全可以用switch来解决这个问题。

发布者

Robinson Zhang

热爱前端,热爱分享,坚持高频写作,从小白到大师只是时间问题。