javascript设计模式之策略模式

 更新时间:2022年01月11日 09:10:32   作者:石头山_S  
这篇文章主要为大家介绍了javascript策略模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

一. 认识策略模式

策略模式的定义:定义一系列的算法,将他们一个个封装起来,使他们直接可以相互替换。

策略模式是开发中常用的第二种设计模式,它在开发中非常常见,由两部分组成。第一部分是策略类,封装了许多具体的,相似的算法。第二部分是环境类,接受客户请求,随后将请求委托给策略类。说的通俗一点就是将相同算法的函数存放在一个包装里边,每个函数用相同的方式拿出来,就叫做策略模式。下面我们来通过代码实现深入了解一下。

二. 具体实现和思想

假如需要实现一个计算员工奖金的程序,效绩为 S 则发基本工资的4倍,A 则3倍,以此类推,那么我们正常实现该代码,是通过判断分支语句来实现。

1. 通过分支实现

        let bonus = function (performance, salary) {
            if(performance === "S") {
                return salary*4;
            }
            if(performance === "A") {
                return salary*3;
            }
            if(performance === "B") {
                return salary*2;
            }
        }

分析:该实现存在显著的缺点,如果随着效绩 的扩展,比如增加C,D,E, if 分支不断累加,使得代码越来越庞大。

因此我们使用策略模式来重构代码。

2.使用策略模式实现

        let performanceS = function () {};
        performanceS.prototype.calculate = function ( salary ) {
            return salary*4
        }
        let performanceA = function () {};
        performanceA.prototype.calculate = function ( salary ) {
            return salary*3
        }
        let performanceB = function () {};
        performanceB.prototype.calculate = function ( salary ) {
            return salary*2
        }
        let performanceC = function () {};
        performanceC.prototype.calculate = function ( salary ) {
            return salary*1
        }
 
        let Bonus = function () {
            this.salary = null; // 原始工资
            this.strategy = null; // 原始绩效
        }
        Bonus.prototype.setSalary = function ( salary ) {
            this.salary = salary;
        }
        Bonus.prototype.setStrategy = function ( strategy ) {
            this.strategy = strategy;
        }
        Bonus.prototype.getBonus = function () {
            if(!this.strategy) {
                throw new Error("未设置绩效");
            }
            return this.strategy.calculate(this.salary);
        }
 
        let bonus = new Bonus();
        bonus.setSalary(10000);
        bonus.setStrategy(new performanceS());
        console.log(bonus.getBonus());

分析:重构后,我们将每种绩效算法单独成一个函数,需要计算某种绩效时只需要将其传入 getBonus 函数中,去掉了 if 分支,减少了性能消耗,并且使代码有了弹性,随时增加其他绩效,不需要更改原代码。

主要思想:这段代码基于面向对象语言,引入了多态的概念,不适用于js。

3. JavaScript 版本的策略模式

        // js中函数也是对象,直接将 strategy 定义为函数
        let strategy = {
            "S": function ( salary ){
                return salary*4;
            },
            "A": function ( salary ) {
                return salary*3;
            },
            "B": function ( salary ) { 
                return salary*2;
            }
        }
        let calculateBonus = function ( level, salary ) {
            return strategy[ level ]( salary );
        }
        console.log(calculateBonus('A', 20000)) // 6000

分析:js 的对象可以直接创建,将函数封装进去,这样一来,代码显得清晰简洁。代码的复用,弹性也随之变强。

以上就是 js 设计模式策略模式的主要思想和实现,他在应用中有两个主要的作用,一是策略模式实现晃动动画;二是实现表单验证,有能力有兴趣的小伙伴可以往下看。

三. 策略模式的实际运用

1. 使用策略模式实现缓存动画

        // 缓动算法
        let tween = {
            linear (t, b, c, d) {
                return c*t/d + b;
            },
            easeIn (t, b, c, d) {
                return c*(t /= d) *t + b;
            },
            strongEaseIn (t, b, c, d) {
                return c*(t /= d) *t *t *t *t + b;
            }
        }
 
        // 定义一个动画类,参数为要运动的 dom 节点
        let Animate = function ( dom ) {
            this.dom = dom;
            this.startTime = 0;
            this.startPos = 0;
            this.endPos = 0;
            this.propertyName = null;
            this.easing = null; // 缓动算法
            this.duration = null;
        }
 
        // 启动方法
        Animate.prototype.start = function (propertyName, endPos, duration, easing) {
            this.startTime =+ new Date;
            this.startPos = this.dom.getBoundingClientRect()[propertyName]; // dom 初始位置
            this.propertyName = propertyName;
            this.endPos = endPos;
            this.duration = duration;
            this.easing = tween[easing];
 
            let self = this;
            let timeId = setInterval(() => {
                if( self.step() === false){
                    clearInterval(timeId);
                }
            }, 19);
        }
 
        // 实现小球每一帧要做的事情
        Animate.prototype.step = function () {
            let t =+ new Date;
            if(t>this.startTime + this.duration){
                this.update(this.endPos);
                return false;
            }
            let pos = this.easing(t - this.startTime, this.startPos, this.endPos - this.startPos, this.duration);
            this.update(pos);
        }
 
        Animate.prototype.update = function (pos) {
            this.dom.style[this.propertyName] = pos + 'px';
        }
 
        let test = function () {
            let div = document.getElementById('div');
            let animate = new Animate(div);
            animate.start('left', 500, 1000, 'strongEaseIn');
            // animate.start('top', 1500,  500, 'strongEaseIn');
        }
        test();

2. 使用策略模式进行表单验证

        let strategies = {
            isNonEmpty ( value, errorMsg) { // 判断是否为空
                if(value === '') {
                    return errorMsg;
                }
            },
            minLength (value, length, errorMsg){
                if (value.length < length) {
                    return errorMsg;
                }
            }
        }
 
        let dom = document.forms[0].acount;
 
        let validatarFunc = function () {
            let validator = new Validator();
            // 添加校验规则
            validator.add(dom, 'isNonEmpty', '用户名不能为空!');
            let errorMsg = validator.start();
            return errorMsg; // 返回校验结果
        }
        
 
        // 实现表单校验保存类
        let Validator = function () {
            this.cache = []; // 保存校验规则
        }
        Validator.prototype.add = function (dom, rule, errorMsg) {
            let ary = rule.split(':');
            this.cache.push( function(){
                let strategy = ary.shift();
                ary.unshift(dom.value);
                ary.push( errorMsg );
                return strategies[strategy].apply(dom, ary);
            })
        }
        Validator.prototype.start = function () {
            for(let i = 0, validatorFunc; validatorFunc = this.cache[i++];){
                let msg = validatorFunc();
                if( msg ) {
                    return msg;
                }
            }
        }
 
        document.forms[0].addEventListener('submit', (e) =>{
            let errorMsg = validatarFunc();
            if(errorMsg){
                alert(errorMsg);
                e.preventDefault();
            }
        })

分析:第一个实现中是把缓动算法封装在一个对象中,调用他们时便于相互替换,也便于扩展。

第二个实现是将校验规则封装起来。

四. 总结

策略模式利用组合、委托、多态等技术思想,有效避免多重条件选择语句,将算法封装在 strategy 中,使他们易于切换、扩展。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

相关文章

  • 详解JavaScript实现异步Ajax

    详解JavaScript实现异步Ajax

    本文详细讲解了JavaScript实现异步Ajax的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • JavaScript预编译和执行过程详解

    JavaScript预编译和执行过程详解

    本文详细讲解了JavaScript预编译和执行过程,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • 实现高性能JavaScript之执行与加载

    实现高性能JavaScript之执行与加载

    avaScript在浏览器中的性能,此问题因JavaScript的阻塞特征而复杂,也就是说JavaScript运行时其他的事情不能被浏览器处理,事实上,大多数浏览器使用单进程处理JavaScript运行等多个任务,而同一时间只能有一个任务被执行。
    2016-01-01
  • 全面理解闭包机制

    全面理解闭包机制

    下面小编就为大家带来一篇全面理解闭包机制。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • 浅谈关于JavaScript API设计的一些建议和准则

    浅谈关于JavaScript API设计的一些建议和准则

    这篇文章主要介绍了浅谈关于JavaScript API设计的一些建议和准则,文中列举了许多知名的JS API进行辅助说明,极力推荐!需要的朋友可以参考下
    2015-06-06
  • JavaScript简介_动力节点Java学院整理

    JavaScript简介_动力节点Java学院整理

    JavaScript是一种基于对象(Object)和事件驱动(EventDriven)并具有安全性能的脚本语言,javascript的出现使得网页和用户之间实现了一种实时性的,动态性的,交互性的关系,使网页包含更多活跃的元素和更加精彩的内容
    2017-06-06
  • 浅析JavaScript异步代码优化

    浅析JavaScript异步代码优化

    这篇文章主要介绍了JavaScript异步代码优化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • JavaScript中window、doucment、body的解释

    JavaScript中window、doucment、body的解释

    JavaScript中window、doucment、body是什么意思呢,下面为大家做个介绍,不知道的朋友可以参考下
    2013-08-08
  • Javascript入门学习第六篇 js DOM编程

    Javascript入门学习第六篇 js DOM编程

    上篇文章纳闷的问题,将在这章和以后的几章里,慢慢搞定。 从今天起,开始学习DOM编程 让我们慢慢称为一名初级的js程序员。 然后往js匠人方向发展。
    2008-07-07
  • JavaScript学习笔记整理_用于模式匹配的String方法

    JavaScript学习笔记整理_用于模式匹配的String方法

    下面小编就为大家带来一篇JavaScript学习笔记整理_用于模式匹配的String方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09

最新评论