浅谈 JavaScript 中策略模式的使用

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

内容简介:策略模式由两部分构成:一部分是封装不同策略的策略组,另一部分是 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 中。


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

查看所有标签

猜你喜欢:

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

疯狂XML讲义

疯狂XML讲义

李刚 / 电子工业出版社 / 2009-11 / 65.00元

《疯狂XML讲义》主要以XML为核心,深入地介绍了XML的各种相关知识。《疯狂XML讲义》作为疯狂Java体系图书之一,依然保持该体系图书系统、全面的特点:不仅详细介绍了XML,文档的各种知识,还通过案例示范了实际开发中如何应用XML知识。 《疯狂XML讲义》主要分为五个部分。第一部分介绍了XML、DTD、XML Schema等基础知识,这些知识主要教读者如何定义有效的XML文档,这部分内容......一起来看看 《疯狂XML讲义》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具