栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > JavaScript

细品 javascript 设计模式(策略模式)

JavaScript 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

细品 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 中添加入下节点

im 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')
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号