资讯专栏INFORMATION COLUMN

听飞狐聊JavaScript设计模式系列15

guyan0319 / 2607人阅读

摘要:介一回,聊策略模式,策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。下一回,聊一聊的享元模式。

本回内容介绍

上一回,聊了聊链式编程,模拟了jQuery和underscore.js,并写了一个遍历多维数组的函数。
介一回,聊策略模式(Strategy),策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

1. 策略模式

先看一个计算奖金的例子,这个在网上的策略模式例子里曝光率很高,如下:

var a = window.alert;
// 定义一个年终奖策略
var strategy = {
    // 传入的是工资,A级别的工资最高,倍数最多
    "A": function(salary) {
        return salary * 5;
    },
    "B": function(salary) {
        return salary * 3;
    },
    "C": function(salary) {
        return salary * 1;
    }
};

// 门面模式记得吧,系列08聊过的,这里就是接收level级别,salary薪资,返回年终奖
function Bonus(level, salary) {
    return strategy[level](salary);
};

// 测试
a(Bonus("C", 10000));    // 10000
a(Bonus("B", 20000));    // 60000
a(Bonus("A", 30000));    // 150000

策略对象封装了具体的算法,然后一个方法接收传参,委托给策略对象进行计算。这个例子很容易理解,很直观。

2. 策略模式之人在囧途

大家都看过电影《人在囧途》吧,两人先是乘飞机,然后乘火车,最后乘汽车,转换为代码如下:

var a = window.alert;
// 接口类,不清楚的盆友请看系列05接口
var TravelStrategy = new Interface("TravelStrategy",["journey"]);

// 飞机类策略
var AirplanelStrategy = function (){
    // 检测是否实现了接口方法
    Interface.ensureImplements(this,TravelStrategy);
}
AirplanelStrategy.prototype = {
    // 还原指针指向本类
    constructor:AirplanelStrategy,
    // 行程策略,这里的策略不具体实现,就弹出一个对白吧
    journey:function(){
        a("大卫第一次坐飞机,登机前喝光了一箱牛奶~");
    }
}

// 火车类策略
var TrainStrategy = function (){
    Interface.ensureImplements(this,TravelStrategy);
}
TrainStrategy.prototype = {
    constructor:TrainStrategy,
    journey:function(){
        a("大卫第一次坐火车,站票~");
    }
}

// 汽车类策略
var BusStrategy = function (){
    Interface.ensureImplements(this,TravelStrategy);
}
BusStrategy.prototype = {
    constructor:BusStrategy,
    journey:function(){
        a("大卫第一次坐汽车,兴奋不已,大唱回家过年~");
    }
}

// 定义一个人的类,其实这个就是上下文环境类,每一次对Strategy对象的请求中都将这个状态传递过去
function Person(travelStrategy ){
    this.strategy = travelStrategy;
}

Person.prototype = {
    constructor:Person,
    setTravelStrategy:function(travelStrategy){
        this.strategy = travelStrategy;
    },
    travel:function(){
        this.strategy.journey();
    }
}

测试部分代码如下:

// 测试部分,没错,又是大卫登场了,首先,大卫囧途,NO1:乘坐飞机回家
var david = new Person(new AirplanelStrategy());  
david.travel();  

// NO2:改策略乘坐火车回家
david = new Person(new TrainStrategy());  
david.travel();  
  
// NO3:该策略乘坐汽车回家  
david.setTravelStrategy(new BusStrategy());  
david.travel(); 

这个例子是根据一个java的策略模式例子改的JS版本,好玩儿吧,又玩儿了一次大卫哥,以后一看到策略模式就会想起“卫囧”。

3. 策略模式之validate

有了上面两个例子的基础,对策略模式有了更深的理解,那介一个例子就来模拟validate,代码如下:
html界面部分




    听飞狐聊设计模式之策略模式






登 录

策略对象部分:

// 策略对象
var strategys = {
    // 判断是否为空,传参为dom元素的值,错误信息
    isNotEmpty: function(value,errMsg) {
        // 值为空,则返回传入的提示信息
        if(value === "") {
            return errMsg;
        }
    },
    // 限制最小长度,如果不符合
    minLength: function(value,length,errMsg) {
        // 传入的dom元素值的长度小于定义的长度,则返回错误信息
        if(value.length < length) {
            return errMsg;
        }
    }
};

下面是校验类的代码,如下:

// 定义验证类
var Validator = function(){
    // 缓存验证策略
    this.cache = [];  
};

Validator.prototype = {
    constructor:Validator,
    // 传入的dom为元素的值,rules为验证规则
    add:function(dom,rules) {
        var self = this;
        // 遍历验证规则数组
        for(var i=0,len=rules.length;i

测试部分代码,如下:

// 代码调用
var btn = document.getElementById("btn");
var sub = document.getElementById("sub");
// 校验环境类
function validateContext(){
    // 创建Validator对象
    var validator = new Validator();
    // 添加一些效验规则
    validator.add(sub.username,[
        {strategy: "isNotEmpty",errMsg:"用户名不能为空"},
        {strategy: "minLength:6",errMsg:"用户名长度不能小于6位"}
    ]);
    validator.add(sub.pwd,[
        {strategy: "minLength:6",errMsg:"密码长度不能小于6位"},
    ]);
    // 获取效验结果
    var errMsg = validator.run();
    // 返回效验信息
    return errMsg;
};
// 点击确定提交
btn.addEventListener("click",function(){
    var errMsg = validateContext();
    // 如果有提示信息则直接提示
    if(errMsg){
        alert(errMsg);
        return false;
    // 否则errMsg为undefined,那么跳转到飞狐系列,嘿嘿~
    }else{
        var url = "http://segmentfault.com/blog/%E9%A3%9E%E7%8B%90";
        window.location.href = url;
    }
},false)

这里就是模拟validator的简版代码了,我没有写太多方法,大家可以扩充。这个例子更贴近实际开发,相信对策略模式会有更深的理解。


装个逼,刚策略模式聊到了人在囧途,突然就想起了《唐人街探案》,其中肖央演的坤泰确实很出彩~~

这一回聊的策略模式,模拟了下validator,难度适中~
下面的内容是一道题,记得系列03里的某客面试题吗,还有一道题是数字转中文, 例:123转一百二十三~

JS数字转中文

中国古代表示数量的单位依次是:个、十、百、千、万、亿、兆、京、垓、秭...这里的单位我就直接copy了。

function convert(num){
    // cn和unit是单位,unit我这里分为两组
    var cn      = ["零","一","二","三","四","五","六","七","八","九"];
    var unit = ["十","百","千"],bigUnit = ["","万","亿","兆","京","垓","杼","穰","沟","涧","正","载"];
    var str  = "";        // 转换字符串
    var arr  = [];        // 结果数组
    var index = 0;        // 单位索引
    var r = [];            // result缩写
    
    if(isNaN(num)){
        throw new Error("输入数字有误,请重新输入数字!");
    }
    
    if(typeof num === "number")    str = str+num;                // 数字转字符串
    else if(typeof num === "string") str = num;
    
    if(str.length>0){
        // 判断如果有小数,则取左边整数
        if(str.indexOf(".")) str = str.split(".")[0];        
        // 拆分字符串到数组
        arr = str.split("");
        // 排除开头为0的情况
        while(arr.indexOf("0")==0){
            arr.shift();
        }                                
    }
    
    // 补位,不满4位就补足4位,如:10->0010;126->0126
    var fill = str.length%4;
    if(fill != 0 ){
        fill = 4 - str.length%4;
        for(var i=0;i

这里就已经可以实现数字转中文了,继续写带有单位的计算转换,接着敲代码吧^_^。

JS数字转中文进阶版

上面例子的基础上,再做每四位一组,遍历单位转换,再加一个判断零的情况,代码如下:

function convert(num){
    // cn和unit是单位,unit我这里分为两组
    var cn      = ["零","一","二","三","四","五","六","七","八","九"];
    var unit = ["十","百","千"],bigUnit = ["","万","亿","兆","京","垓","杼","穰","沟","涧","正","载"];
    var str  = "";        // 转换字符串
    var arr  = [];        // 结果数组
    var index = 0;        // 单位索引
    var r = [];            // result缩写
    
    if(isNaN(num)){
        throw new Error("输入数字有误,请重新输入数字!");
    }
    
    if(typeof num === "number")    str = str+num;                // 数字转字符串
    else if(typeof num === "string") str = num;
    
    if(str.length>0){
        // 判断如果有小数,则取左边整数
        if(str.indexOf(".")) str = str.split(".")[0];        
        // 拆分字符串到数组
        arr = str.split("");
        // 排除开头为0的情况
        while(arr.indexOf("0")==0){
            arr.shift();
        }                                    
    }
    
    // 补位,不满4位就补足4位,如:10->0010;126->0126
    var fill = str.length%4;
    if(fill != 0 ){
        fill = 4 - str.length%4;
        for(var i=0;i0){
        var o = {};
        // 按照四位一组
        for(var i=0;i

这就是完整的代码了,我没有做更多的测试,只能算是粗略的完成了,确实是简单粗暴的敲完了代码,其实再完美一点,在判断零的时候还可以计算,整体代码还可以优化算法,更简单,性能更优化,抛砖引玉,这个就给大家继续完善了,优化了这个例子的童鞋,也分享分享呗,可以直接评论,多碰撞碰撞,大家一起进步呗,嘿嘿~~

这一回,主要策略模式,模拟了validate,做了一道题数字转中文的题。
下一回,聊一聊JS的享元模式。

客观看完点个赞,推荐推荐呗,嘿嘿~~

注:此系飞狐原创,转载请注明出处

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91602.html

相关文章

  • 飞狐JavaScript设计模式系列03

    摘要:闭包与柯里化闭包有权访问另一个函数作用域中变量的函数。柯里化把接受多个参数的函数变换成接受一个单一参数最初函数的第一个参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术。 本回内容介绍 上一回聊到JS的Object类型,简单模拟了一下Java的Map,介一讲,偶们来聊一下函数好唔好,介可系JS世界的一等公民哟。从函数开始,我们就将逐步过渡到设计模式,来吧,帅狐带你装逼带你飞:...

    levy9527 评论0 收藏0
  • 飞狐JavaScript设计模式系列06

    本回内容介绍 上一回聊到JS中模拟接口,装饰者模式,掺元类,分析了backbone的继承源码,感觉还好吧! 介一回,偶们来聊一下在JS单例模式(singleton),单例模式其实运用很广泛,比如:jquery,AngularJS,underscore吖虾米的都是单例模式,来吧,直接开始咯: 1. 单例模式 保证一个类只有一个实例,从全局命名空间里提供一个唯一的访问点来访问该对象。其实之前写过的对象...

    hiYoHoo 评论0 收藏0
  • 飞狐JavaScript设计模式系列02

    摘要:本回内容介绍上一回聊到数据类型,简单的过了一遍,包括个数组新特性等,这一回来聊聊对象,结合数组来实战一些例子,在做题中成长,记忆会更深刻,来吧,开始咯创建实例的方式有两种使用操作符后跟构造函数飞狐使用对象字面量表示法飞狐也可以飞狐这种写法与 本回内容介绍 上一回聊到JS数据类型,简单的过了一遍,包括9个数组新特性等,这一回来聊聊Object对象,结合数组来实战一些例子,在做题中成长,记...

    tangr206 评论0 收藏0
  • 飞狐JavaScript设计模式系列11

    摘要:桥接模式之特权函数特权函数,用一些具有特权的方法作为桥梁以便访问私有空间,可以回忆一下之前的系列。连续自然数分组,计算最多组的个数将至这个连续自然数分成组使每组相加的值相等。个数组中数字最多的一组有个此时的和为。 本回内容介绍 上一回,聊了适配器模式,图片预加载,介一回,聊桥接模式(Bridge),跟之前一样,难度比较小,桥接模式将抽象部分与它的实现部分分离,通过桥接模式联系彼此,同时...

    wanglu1209 评论0 收藏0
  • 飞狐JavaScript设计模式系列10

    摘要:本回内容介绍上一回,聊了代理模式,虚拟代理,图片懒加载,介一回,也比较容易,适配器模式,用一个新的接口对现有类的接口进行包装,处理类与的不匹配。这一回,主要聊了适配器模式,图片预加载,主要还是理解下一回,聊一聊桥接模式,顺便做一做计算题。 本回内容介绍 上一回,聊了代理模式,虚拟代理,图片懒加载,介一回,也比较容易,适配器模式(Adapter),用一个新的接口对现有类的接口进行包装,处...

    yexiaobai 评论0 收藏0

发表评论

0条评论

guyan0319

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<