装饰器模式

文章目录

  • 一、定义
  • 二、实现
  • 三、应用
    • 3.1 表单校验与表单提交分离
    • 3.2 mock接口请求前打印出请求参数
  • 四、总结


一、定义

装饰器就是动态给对象添加职责。

二、实现

aop实现方式。

/*在方法调用之前添加职责(功能) */
Function.prototype.before = function (beforefn) {
    var __self = this;  // 保存原函数的引用 
    return function () {    // 返回包含了原函数和新函数的"代理"函数 
        beforefn.apply(this, arguments);  // 执行新函数,且保证this不被劫持,新函数接受的参数 
        // 也会被原封不动地传入原函数,新函数在原函数之前执行 
        return __self.apply(this, arguments);  // 执行原函数并返回原函数的执行结果, // 并且保证this不被劫持 
    }
}
/**在方法调用之后添加功能 */
Function.prototype.after = function (afterfn) {
    var __self = this; return function () {
        var ret = __self.apply(this, arguments);
        afterfn.apply(this, arguments); return ret;
    }
};

var ajax = function (type, url, param) {
    console.log(param);     // 发送 ajax 请求的代码略 
};
var getToken = function () { return 'Token'; }
ajax = ajax.before(function (type, url, param) {
    param.Token = getToken();
});
ajax('get', 'http:// xxx.com/userinfo', { name: 'sven' }); 

使用装饰器模式可以改变函数的参数,如上面,我们使用beforeajax的参数增加了一个token参数。

三、应用

3.1 表单校验与表单提交分离

表单提交中,将表单校验和表单提交分离开来,避免原本的表单提交函数过于臃肿,符合单一职责原则

Function.prototype.before = function(beforefn) {
    var __self = this;
    return function() {
        if (beforefn.apply(this, arguments) === false) {
            // beforefn返回false的情况直接return,不再执行后面的原函数 
            return;
        }
        return __self.apply(this, arguments);
    }
}
/**模拟表单空间的数据 */
var username = ''
  , password = '123'
var validata = function() {
    if (username === '') {
        alert('用户名不能为空');
        return false;
    }
    if (password === '') {
        alert('密码不能为空');
        return false;
    }
}
var ajax = function(type, url, param) {
    console.log(param);
    // 发送 ajax 请求的代码略 
};
var formSubmit = function() {
    var param = {
        username: username.value,
        password: password.value
    }
    ajax('http:// xxx.com/login', param);
}
formSubmit = formSubmit.before(validata);
formSubmit();

3.2 mock接口请求前打印出请求参数

在进入mock接口时,打印出请求参数query(url)和body(主体)

/**
 *   @auther fengli
 *   使用了装饰器模式,给方法添加打印功能
*/

/**
 * 在方法调用之前添加职责(功能)
 *
 * @author fengli
 * @date 2020-05-07
 * @export
 * @param {*} fn
 * @param {*} beforefn
 * @returns
 */
export function before(fn, beforefn) {
    return function (req, res) {    // 返回包含了原函数和新函数的"代理"函数 
        beforefn.apply(this, arguments);  // 执行新函数,且保证this不被劫持,新函数接受的参数 
        // 也会被原封不动地传入原函数,新函数在原函数之前执行 
        return fn.apply(this, arguments);  // 执行原函数并返回原函数的执行结果, // 并且保证this不被劫持 
    }
}


/**
 * 在方法调用之后添加功能
 *
 * @author fengli
 * @date 2020-05-07
 * @export
 * @param {*} fn
 * @param {*} afterfn
 * @returns
 */
export function after(fn, afterfn) {
    return function () {
        var ret = fn.apply(this, arguments);
        afterfn.apply(this, arguments);
        return ret;
    }
}


/**
 * 打印处request的url及请求参数
 *
 * @author fengli
 * @date 2020-05-07
 * @export
 * @param {*} req
 */
export function logReq(req) {
    console.log('url:', req.originalUrl);
    console.log('query:', req.query);
    console.log('body', req.body);
}

export function logRes(req, res) {
    //console.log('res', res.getHeaderNames())
}

mock接口

import { before, logReq } from './log'

export default {
  'GET /api/protectionZoneFillSubmit/getListByPage': before(getListByPage, logReq),
};

function getListByPage(req, res) {
  const template = {
    'id|+1': 1,
    'submitTime|1': [2015, 2016, 2017, 2018, 2019, 2020],
    'name|1': ['府河支流徐家河水域银鱼国家级水产种质资源保护区', '堵河鳜国家级水产种质资源保护区', '汉江郧县段翘嘴鲌国家级水产种质资源保护区'],
    'latitude|1': ['北纬31.200000°——31°', '北纬32°——32.111°', '北纬32.01°——32.59°'],
    'longitude|1': ['东经113.12°——113.45°', '东经110.31°——110.31°', '东经110°——111°'],
    'currentProtectionArea|1': [3840, 4000, 1250],
    'majorProtectObject|1': ['银鱼', '鳜、大眼鳜、斑鳜,其它保护对象包括蒙古鲌、鲶、鲢、鳙等重要经济鱼类及其生态环境', '翘嘴鲌、蒙古红鲌、拟尖头红鲌、鳡鱼、青草鲢鳙'],
    'approveTime|1': ['2014-11-25', '2013-11-11'],
    'approveDocNumber|1': ['中华人民共和国农业部公告第2181号', '中华人民共和国农业部公告〔2018〕号'],
    'managerOrgName|1': ['广水市水产局渔政执法大队', '十堰市郧阳区水产局'],
    submitUnit: '湖北省-随州市-广水市',
    'status|1': ['省审批', '专家审批', '已通过', '被驳回', '未上报']
  };
  const { pageSize, pageNo } = req.query;
  let nameAndRule = `records|${pageSize}`;
  let tempObj = {};
  tempObj[nameAndRule] = [template];
  const data = Mock.mock(tempObj)
  data.total = 100;
  data.current = +pageNo;
  data.size = +pageSize;
  return res.json({ code: 200, data: data })
}

四、总结

装饰器模式就是动态给对象添加职责

代理模式和装饰者模式最重要的区别在于它们的意图和设计目的。代理模式的目的是,当直 接访问本体不方便或者不符合需要时,为这个本体提供一个替代者。本体定义了关键功能,而代 理提供或拒绝对它的访问,或者在访问本体之前做一些额外的事情。装饰者模式的作用就是为对 象动态加入行为。换句话说,代理模式强调一种关系(Proxy与它的实体之间的关系) ,这种关系 可以静态的表达,也就是说,这种关系在一开始就可以被确定。而装饰者模式用于一开始不能确 定对象的全部功能时。代理模式通常只有一层代理本体的引用,而装饰者模式经常会形成一条 长长的装饰链。

java中的装饰器模式

你可能感兴趣的:(js设计模式)