浅谈 JavaScript 中策略模式的使用

栏目: 后端 · 发布时间: 6年前

内容简介:策略模式由两部分构成:一部分是封装不同策略的策略组,另一部分是 Context。通过组合和委托来让 Context 拥有执行策略的能力,从而实现易扩展、易理解,并且避免大量复制粘贴的工作。策略模式的典型应用场景是表单校验中,对于校验规则的封装。接下来通过两个例子简单了解下 JavaScript 中策略模式的使用:因为百度AI图像识别的接口类型不同,所需的参数格式也不尽相同。然而图像的压缩及上传、错误处理等部分是公用的。所以可以采用策略模式封装:

策略模式由两部分构成:一部分是封装不同策略的策略组,另一部分是 Context。通过组合和委托来让 Context 拥有执行策略的能力,从而实现易扩展、易理解,并且避免大量复制粘贴的工作。策略模式的典型应用场景是表单校验中,对于校验规则的封装。

接下来通过两个例子简单了解下 JavaScript 中策略模式的使用:

使用策略模式调用百度AI图像识别

因为百度AI图像识别的接口类型不同,所需的参数格式也不尽相同。然而图像的压缩及上传、错误处理等部分是公用的。所以可以采用策略模式封装:

定义策略组

通过定义策略组来封装不同的接口及其参数:比如身份证识别接口的 side 字段,自定义识别的 templateSign 字段,以及行驶证识别的接收参数为 poparamstData

/**
 * 策略组
 * IDCARD:身份证识别
 * CUSTOMIZED:自定义识别
 * VL:行驶证识别
 */
var strategies = {
    IDCARD: function (base64) {
        return {
            path: 'idcard',
            param: {
                'side': 'front',
                'base64': base64
            }
        };
    },

    CUSTOMIZED: function (base64) {
        return {
            path: 'customized',
            param: {
                'templateSign': '52cc2d402155xxxx',
                'base64': base64
            }
        };
    },
    VL: function (base64) {
        return {
            path: 'vehicled',
            poparamstData: {
                'base64': base64
            }
        };
    },
};
复制代码

定义 Context

var ImageReader = function () { };

/**
 * 读取图像,调用接口,获取识别结果
 * 
 * @param {*} type 待识别文件类型
 * @param {*} base64 待识别文件 BASE64码
 * @param {*} callBack 识别结果回调
 */
ImageReader.prototype.getOcrResult = function (type, base64, callBack) {
    let fileSize = (base64.length / (1024 * 1024)).toFixed(2);
    let compressedBase64 = '';
    let image = new Image();
    image.src = base64;
    image.onload = function () {
        /**
         * 图片压缩处理及异常处理,代码略
         */
         

        let postData = strategies[type](compressedBase64);

        ajax(
            host + postData.path, {
                data: postData.param,
                type: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                success: function (res) {
                    var data = JSON.parse(res);
                    // 暴露给 UI 层的统一的错误码
                    if (data.error_code !== undefined && data.error_code !== 0) {
                        var errorData = {
                            error: 1,
                            title: '错误 ' + data.error_code,
                            content: 'error message'
                        };
                        callBack(errorData);
                    } else {
                        callBack(data);
                    }
                }
            });
    };
};


复制代码

调用方式

var imageReader = new ImageReader();
imageReader.getOcrResult('IDCARD', this.result.toString(), callback);
复制代码

策略模式封装 Vue Select 组件

某项目中多处用到了 element-ui 的 select 组件,其内在逻辑类似,都是初始化时获取下拉列表的数据源,然后在选中某一项时 dispatch 不同的 action。遂考虑使用策略模式封装。

Context

在本例中,组件向外部暴露一个 prop,调用方指定该 prop 从而加载不同的策略。那么定义 Context 如下:

<template>
  <el-select v-model="selectedValue" placeholder="请选择" @change="optionChanged" size="mini" clearable>
    <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id">
    </el-option>
  </el-select>
</template>
复制代码
data() {
    return {
      selectedValue: undefined,
      options: [],
      action: "",
    };
  },
  props: {
    // 暴露给外部的 select-type
    selectType: {
      type: String
    },
  },
  created() {
   // 获取 options
   this.valuation();
  },
    methods: {
    optionChanged() {
      this.$emit(this.action, this.selectedValue);
    },
    setOptions(option) {
      this.$store.dispatch(this.action, option);
    },
    valuation() {
      // 获取 options 数据
    }
  },
复制代码

外部通过如下方式调用组件:

<MySelect selectType="product"/>
复制代码

strategies

然后定义策略组:

let strategies = {
    source: {
        action: "sourceOption",
        getOptions:  function() {
            // 拉取 options
        }
    },
    product: {
        action: "productOption",
        getOptions:  function() {
            // 拉取 options
        }
    },
    ...
}
复制代码

异步

至此该组件的基本结构已经清晰,但还存在一个问题:组件加载时是异步拉取的 options, 而页面初始化的时候很可能 options 还没有返回,导致 select 的 options 仍为空。所以此处应该修改代码,同步获取 options:

// 策略组修改
source: {
    action: "sourceOption",
    getOptions: async function() {
        // await 拉取 options
    }
  },
// 组件修改
methods: {
    ...
    async valuation() {
        ...
    }
}
复制代码

继续优化

但我们不是每次加载组件都需要拉取 options,如果这些 options 在其他组件或者页面也被使用到,那么可以考虑将其存入 vuex 中。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Linux程序设计

Linux程序设计

Neil Matthew、Richard Stones / 陈健、宋健建 / 人民邮电出版社 / 201005 / 99.00元

时至今日,Linux系统已经从一个个人作品发展为可以用于各种关键任务的成熟、高效和稳定的操作系统,因为具备跨平台、开源、支持众多应用软件和网络协议等优点,它得到了各大主流软硬件厂商的支持,也成为广大程序设计人员理想的开发平台。 本书是Linux程序设计领域的经典名著,以简单易懂、内容全面和示例丰富而受到广泛好评。中文版前两版出版后,在国内的Linux爱好者和程序员中也引起了强烈反响,这一热潮......一起来看看 《Linux程序设计》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试