zoukankan      html  css  js  c++  java
  • 细品 javascript 设计模式(策略模式)

    我尽量用最少的文字,最少的篇幅,讲明白设计模式的方方面面。
    全文连接

    理解策略模式

    把 算法 和 调用算法 的部分做拆分开
    

    我举个例子吧:你想要去三亚旅游,途径有很多种:飞机,火车,自驾游。这几种方法都可以到达目的地,但是过程是有所不同的。

    • 飞机:适合紧急不差钱的情况
    • 火车:适合不紧急,并且目的明确(公司团建,中老年旅游)
    • 自驾游:这种比较随性,和朋友家人一起出门,一起欣赏路过的风景。

    每一种选择,都是一种策略。
    在程序中策略的意义在于,把处理不同任务但目的相同的代码整合在一起。再用一层函数委托他们来处理具体的算法。这样可以消除原本程序中大片的条件分支语句

    上代码: 策略模式(计算不同的旅行方式到达时间)

    // 定义策略
    var strategies = {
        'plane': function(distance) {
            return distance * 1; // 假设飞机的速度最快
        },
        'train': function(distance) {
            return distance * 4; // 飞机的速度是火车的4倍
        },
        'roadTrip': function(distance) {
            return distance * 10; // 飞机的速度是自驾游的10倍
        },
    }
    
    // Context
    var calculateBonus = function(mode, distance) {
        if (typeof strategies[mode] === 'function') {
            return strategies[mode](distance);
        }
        return -1;
    }
    
    // 调用策略
    console.log(calculateBonus('plane', 1000));
    console.log(calculateBonus('train', 1000));
    console.log(calculateBonus('roadTrip', 1000));
    
    策略模式是比较好理解的,咱们先看一段即将被策略模式改造的代码
    

    使用策略模式之前

    var calculateBonus = function(mode, distance) {
        if (mode === 'plane') {
            return distance * 1;
        } else if (mode === 'train') {
            return distance * 4;
        } else if (mode === 'roadTrip') {
            return distance * 10;
        }
        return -1;
    }
    

    这段代码最大的问题是, 代码可复制性差, 不利于维护。每次有新的改动都必须扒开代码,找到具体的某个函数去修改。效率低,容易引发连贯性错误。

    使用策略模式,实现缓懂动画函数

    为了更加明确策略模式的使用场景,我们一起来实现一个动画函数。
    

    js 动画原理改变 dom 的 css 属性,比如 left, top, background-position。所以至少要提供一下一些信息。

    • dom 最初的位置
    • 目标位置
    • 开始时间
    • 结束时间

    然后配合定时器 setInterval 在定时器中每个 19 毫秒改变一次 dom 的 css 属性,每次修改 dom 时把上面的4个参数传给算法。算法会计算出当前应该所在的位置。最后在更新 dom 的 css 属性。这样动画就完成了。

    算法部分,这里最初来自 Flash 但现在 css3 部分也是这样实现的

    在线体验

    // 先定义动画缓动算法
    var tween = {
        linear: function(t, b, c, d) {
            return c * t / d + b;
        },
        easeIn: function(t, b, c, d) {
            return c * (t /= d) * t + b;
        },
        strongEaseIn: function(t, b, c, d) {
            return c * (t /= d) * t * t * t * t + b;
        },
        strongEaseOut: function(t, b, c, d) {
            return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
        },
        sineaseIn: function(t, b, c, d) {
            return c * (t /= d) * t * t + b;
        },
        sineaseOut: function(t, b, c, d) {
            return c * ((t = t / d - 1) * t * t + 1) + b;
        }
    }
    

    然后在 body 中添加入下节点

    <div style="position: absolute; background:yellow;">im div</div>
    

    接下来定义动画类

    let Animate = function(dom) {
        this.dom = dom;
        this.startTime = 0;
        this.startPos = 0;
        this.endPos = 0;
        this.propertyName = null;
        this.esing = null;
        this.duratin = null;
    }
    Animate.prototype.start = function(propertyName, endPos, duratin, esing) {
        this.startTime = Date.now();
        this.startPos = this.dom.getBoundingClientRect()[propertyName];
        this.propertyName = propertyName;
        this.endPos = endPos;
        this.duratin = duratin;
        this.esing = tween[esing];
        let self = this;
        let timeId = setInterval(function() {
            if (self.step() === false) {
                clearInterval(timeId)
            }
        }, 19)
    }
    Animate.prototype.step = function() {
        var t = Date.now();
        if (t >= this.startTime + this.duratin) {
            this.update(this.endPos)
            return false
        }
        var pos = this.esing(
            t - this.startTime, // 时间
            this.startPos, // 开始值
            this.endPos - this.startPos, // 运动距离
            this.duratin // 总耗时
        )
        this.update(pos);
    }
    Animate.prototype.update = function(pos) {
        this.dom.style[this.propertyName] = pos + 'px';
    }
    

    来测试一下!

    var div = document.getElementsByTagName('div')[0];
    var animate = new Animate(div);
    
    animate.start('left', 500, 1000, 'linear')
    // animate.start('left', 500, 1000, 'easeIn')
    // animate.start('left', 500, 1000, 'strongEaseIn')
    // animate.start('left', 500, 1000, 'strongEaseOut')
    // animate.start('left', 500, 1000, 'sineaseIn')
    // animate.start('left', 500, 1000, 'sineaseOut')
    

  • 相关阅读:
    LIst判断是否为空
    SYBASE数据库基本操作
    Java内部类详解--成员内部类,局部内部类,匿名内部类,静态内部类
    String转jsonarry:字符串:[{"result":"20"},{"result":"21"},{"result":"20"},{"result":"22"}]
    使用HttpURLConnection发送POST请求
    Java 定义字符串数组
    JSP 解决illegal to have multiple occurrences of contentType with different values错误
    javascript 获取url参数值
    外键为','(逗号)拼接ID,连接查询外键表ID
    excel、csv、txt文件数据读取
  • 原文地址:https://www.cnblogs.com/shixinglong/p/13169423.html
Copyright © 2011-2022 走看看