javascript设计模式之策略模式

  相信有很多人在开发过程当中都遇到一大串的if/else判断,代码又臭又长,并且随着需求的增长与产品的迭代,判断条件可能愈来愈长,愈来愈难以维护,有没有什么好的方式去解决这种弊端呢?答案是确定的,策略模式是一种很好的解决办法,能够帮助咱们重构规范业务代码,提升代码的可读性与可维护性。算法

  首先,策略模式什么?ui

    策略模式就是定义一系列的算法,把他们各自封装成策略类,算法被封装在策略类内部的方法里。在客户对Context发起请求时,Context老是把请求委托给这些策略对象中间的某一个进行计算。this

    简单来讲,就是将业务逻辑中公有的部分提取出来,封装成一个环境类Context,具体的业务实现过程封装在策略类strategies中,业务请求经过环境类去调用策略类中的实现过程,经过环境类给业务请求以响应消息,其中环境类充当一层代理,将类似的业务逻辑进行总结概括整理,提升代码的可读性与可维护性。本文以表单验证为例,来介绍策略模式在实际开发中的使用。spa

  策略模式最起码由两部分组成:prototype

    一、策略类代理

      封装某个策略的具体实现方法code

    二、环境类Contextorm

      接收客户端业务处理请求,根据请求参数,调用策略类中具体的实现方法,策略类中必需要有处理方法;对象

  以表单验证为例,其策略模式的实现过程以下:blog

function isFunction(fn) {
    return Object.prototype.toString.call(fn) === '[object Function]'
}

function isObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]'
}
/**
 * 策略实现类
 */
const validateStrategies = {
    checkPattern: {
        mobileReg: /^(((13[0-9]{1})|(14[0-9]{1})|(15[0-9]{1})|(16[0-9]{1})|(17[0-9]{1})|(18[0-9]{1})|(19[0-9]{1}))+\d{8})$/,
        numReg: /^[0-9]+(\.[0-9]{1,2})?$/
    },
    validateMobile(item) {
        let flag = true;
        if (item.data && !this.checkPattern.mobileReg.test(item.data)) {
            flag = false;
        }
        return flag;
    },
    validateNumber(item) {
        let flag = true;
        if (!this.checkPattern.numReg.test(item.data)) {
            flag = false;
        } else if (item.point) {
            let pattern = new RegExp(`^[0-9]+(\.[0-9]{1,${item.point}})?$`);
            if (!pattern.test(item.data)) {
                flag = false;
            }
        }
        return flag;
    },
    //校验字段是否必填
    validateRequired(item) {
        let flag = true;
        if (!item.data) {
            flag = false;
        } else {
            flag = true;
        }
        return flag;
    }
};


class ValidateForm {

    constructor() {
        this.cache = [];
    }

    add(rules) {
        if (Array.isArray(rules)) {
            this.cache = [...this.cache, ...rules];
        } else if (isObject(rules)) {
            this.cache = [...this.cache, rules];
        } else {
            messagee.error(`参数类型应该为Object或Array,可是却传入了${typeof rules}`, 2);
        }

    }

    remove(id) {
        let index = this.cache.findIndex(vv => vv.id && Object.is(vv.id, id));
        this.cache.splice(index, 1);
    }

    start() {
        for (let i = 0, len = this.cache.length; i < len; i++) {
            let item = this.cache[i];
            //传入的验证方法必须是一个function
            if (!isFunction(validateStrategies[item.validateFun])) {
                message.error('表单校验参数格式错误', 2);
                return false;
            } else {
                let flag = validateStrategies[item.validateFun](item);
                if (!flag) {
                    return flag;
                }
            }
        }
        return true;
    }
}

export default ValidateForm;

  上述代码,咱们声明了一个ValidateForm类和一个validateStrategies策略对象,策略对象中封装了一些表单验证方法,在实例化Validate表单验证类的时候,须要往表单验证类中注入特定的表单校验规则,而后调用下启动方法,就能获得表单验证结果,以上代码使用过程以下:

 *  一、let validate = new ValidateForm();
 *  二、加入验证规则 validate.add(rules:Array<Object>)
 *  3、开始校验 validate.start()
 *  @param rules:Array<Object> {
 *    validateFun: '', //校验方法
 *    data: '',//校验的数据
 *    maxSize: '', //最大值
 *    ponit: '' //小数点
 *      ...
 *  }

  其中validateFun对应的是策略类中具体的方法名,其他参数能够根据业务需求酌情添加。饶了一大圈,这么作的好处是什么呢?

    一、易维护扩展

      如表单验证,在添加验证规则时,只须要加入一个具体的策略实现方法便可,不须要额外改动其余业务代码

    二、可读性较高

      熟悉某个具体功能逻辑不须要看一些不相关的内容

    三、代码复用性较高

      利用排列组合的方式,能够提升代码的复用性

相关文章
相关标签/搜索