JavaScript设计模式(二十):命令模式

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 命令模式

命令模式(Command)

将请求与实现解耦并封装成独立对象,从而使不同的请求对客户端的实现参数化。

自由化创建视图命令

image.png

<style>
    #title-box .title .main h2{
    
    
        text-align: center;
    }
    #title-box .title .main p{
    
    
        text-align: right;
    }
    #picture-box {
    
    
        text-align: center;
    }
    #picture-box .picture{
    
    
        position: relative;
        display: inline-block;
        margin: 10px;
        border: 1px solid #333;
    }
    #picture-box .picture p{
    
    
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        height: 30px;
        line-height: 30px;
        text-align: center;
        margin: 0;
        background-color: rgba(0, 0, 0, .5);
        color: #fff;
    }
</style>
<body>
    <div id="title-box"></div>
    <div id="picture-box"></div>
</body>
// 模块实现模块
var viewCommand = (function () {
   
   

    // 模板
    let tpl = {
   
   
        // 标题结构模板
        title:
            `<div class="title">
                <div class="main">
                    <h2>{#title#}</h2>
                    <p>{#tips#}</p>
                </div>
            </div>`,
        // 图片结构模板
        picture:
            `<div class="picture">
                <img src="{#src#}"/>
                <p>{#text#}</p>
            </div>`,
    };

    // 存储经过格式化最终返回的html
    let html = '';

    /**
     * 格式化字符串将
     * @param {string} str 原字符串 
     * @param {object} obj 模板数据
     * @returns 最终解析好的html字符串
     */
    function formateString(str, data) {
   
   
        return str.replace(/\{#(\w+)#\}/g, function (_match, key) {
   
   
            return data[key];
        })
    }
    // html = formateString(tpl.title, {title: 'You瞧谁不起 - 道不尽世间的沧桑,诉不完人生的悲凉', tips: '人海茫茫,你我依旧孤独~~~'});
    // document.body.innerHTML = html;
    // console.log(html);

    // 定义指令
    let Action = {
   
   
        /**
         * 解析数据方法html变量中
         * @param {string} view 模板视图
         * @param {object} data 数据
         */
        create(view, data) {
   
   
            // 针对数组的模板解析d
            if (Array.isArray(data)) {
   
   
                data.forEach(d => {
   
   
                    html += formateString(tpl[view], d);
                })
            }
            // 针对对象的模板解析
            else {
   
   
                html += formateString(tpl[view], data);
            }
        },
        /**
         * 展示html到指定容器内,如果此时定义了模板数据解析那么追加模板
         * @param {string} id DOM ID
         * @param {string} view 模板视图(追加)
         * @param {object} data 数据
         */
        display(id, view, data) {
   
   
            console.log(id, view, data);
            if (data) {
   
   
                this.create(view, data); // 追加模板
            }
            console.log(html);
            document.getElementById(id).innerHTML = html;
            html = ''; // 展示后清空缓存的字符串
        }
    };

    /**
     * 命令接口
     * @param {object} param
     *  {
     *      @param {Array} params   数组参数 create->[view, data] display->[id, view, data]
     *      @param {string} command 指令-create/display
     *  }
     */
    return function excute({
   
    params, command }) {
   
   
        // 将参数转转换未数组
        params = Array.isArray(params) ? params : [params];
        // 执行指令
        Action[command].apply(Action, params);
    }
})();

const objData = {
   
   
    title: 'You瞧谁不起 - 道不尽世间的沧桑,诉不完人生的悲凉',
    tips: '人海茫茫,你我依旧孤独~~~'
};

// 渲染标题模块DOM
viewCommand({
   
   
    command: 'display',
    params: ['title-box', 'title', objData]
});


const listData1 = [
    {
   
    text: '图片01', src: 'https://dummyimage.com/200x100/ff0/fff' },
    {
   
    text: '图片02', src: 'https://dummyimage.com/200x100/0ff/fff' },
    {
   
    text: '图片03', src: 'https://dummyimage.com/200x100/0f0/fff' },
];

const listData2 = [
    {
   
    text: '图片04', src: 'https://dummyimage.com/200x100/f0f/fff' },
    {
   
    text: '图片05', src: 'https://dummyimage.com/200x100/00f/fff' },
    {
   
    text: '图片06', src: 'https://dummyimage.com/200x100/f00/fff' },
];

// 暂存使用listData1解析 出来的html字符串
viewCommand({
   
   
    command: 'create',
    params: ['picture', listData1]
});

// 渲染 暂存的 和 使用listData2解析 出来的html字符串
viewCommand({
   
   
    command: 'display',
    params: ['picture-box', 'picture', listData2]
});

绘图命令

image.png

// 绘图指令
var CanvasCommand = (function () {
   
   
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    // 指令方法
    var Action = {
   
   
        /**
         * 填充色彩
         * @param {string} c 颜色
         */
        fillStyle(c) {
   
   
            ctx.fillStyle = c;
        },

        /**
         * 填充矩形
         * @param {number} x 位置x
         * @param {number} y 位置y
         * @param {number} w 矩形宽度
         * @param {number} h 矩形高度
         */
        fillRect(x, y, w, h) {
   
   
            ctx.fillRect(x, y, w, h);
        },

        /**
         * 描边色彩
         * @param {string} c 颜色
         */
        strokeStyle(c) {
   
   
            ctx.strokeStyle = c;
        },

        /**
         * 描边矩形
         * @param {number} x 位置x
         * @param {number} y 位置y
         * @param {number} w 矩形宽度
         * @param {number} h 矩形高度
         */
        strokeRect(x, y, width, height) {
   
   
            ctx.strokeRect(x, y, width, height);
        },

        /** ...CODE... */
    };

    // 命令接口
    return function (data) {
   
   
        data = Array.isArray(data) ? data : [data];
        data.forEach(d => {
   
   
            let params = Array.isArray(d.params) ? d.params : [d.params];
            Action[d.command].apply(Action, params);
        })
    }
})();

// 执行多个指令
CanvasCommand([
    {
   
    command: 'fillStyle', params: 'red' },
    {
   
    command: 'fillRect', params: [20, 20, 100, 100] }
]);

// 执行单个指令
CanvasCommand({
   
   
    command: 'fillRect',
    params: [150, 20, 50, 50],
});

特点:

不用关心每种方法的具体实现了,即使在不同浏览器实现不一致我们也不用关心,因为那些不兼容的问题都已经在命令对象内部实现了

命令模式是将执行的命令封装,解决命令的发起者命令的执行者之间的耦合

每条命令实质上是一个操作。命令的 使用者 不必了解 命令的执行者(命令对象)的命令接口如何实现的、命令是如何接受的、命令是如何执行的。所有的命令都被存储在命令对象中

  • 优点
    • 解决命令使用者之间的耦合;
    • 新的命令很容易加入到命令系统中,供使用者使用;
    • 命令的使用具有一致性,多数的命令在一定程度上是简化操作方法的使用的;
  • 缺点
    • 命令模式是对一些操作的封装,这就造成每执行一次操作都要调用一次命令对象,增加了系统的复杂度;
目录
相关文章
|
1月前
|
设计模式 JavaScript 前端开发
JavaScript设计模式--访问者模式
【10月更文挑战第1天】
31 3
|
2月前
|
设计模式 存储 算法
Java设计模式-命令模式(16)
Java设计模式-命令模式(16)
|
3月前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
51 1
|
3月前
|
设计模式 JavaScript 前端开发
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
|
3月前
|
设计模式 存储 Java
【十二】设计模式~~~行为型模式~~~命令模式(Java)
文章详细介绍了命令模式(Command Pattern),这是一种对象行为型模式,用于将请求封装成对象,实现请求发送者与接收者的解耦,从而降低系统耦合度、提高灵活性,并支持命令的排队、记录、撤销和恢复操作。通过案例分析、结构图、时序图和代码示例,文章展示了命令模式的组成部分、实现方式和应用场景,并讨论了其优点、缺点和适用情况。
|
4月前
|
设计模式 JavaScript Go
js设计模式【详解】—— 状态模式
js设计模式【详解】—— 状态模式
80 7
|
4月前
|
设计模式 JavaScript
js设计模式【详解】—— 桥接模式
js设计模式【详解】—— 桥接模式
70 6
|
4月前
|
设计模式 JavaScript
js设计模式【详解】—— 原型模式
js设计模式【详解】—— 原型模式
50 6
|
4月前
|
设计模式 JavaScript 算法
js设计模式【详解】—— 模板方法模式
js设计模式【详解】—— 模板方法模式
48 6
|
4月前
|
设计模式 JavaScript 前端开发
JavaScript进阶 - JavaScript设计模式
【7月更文挑战第7天】在软件工程中,设计模式是解决常见问题的标准解决方案。JavaScript中的工厂模式用于对象创建,但过度使用可能导致抽象过度和缺乏灵活性。单例模式确保唯一实例,但应注意避免全局状态和过度使用。观察者模式实现了一对多依赖,需警惕性能影响和循环依赖。通过理解模式的优缺点,能提升代码质量。例如,工厂模式通过`createShape`函数动态创建对象;单例模式用闭包保证唯一实例;观察者模式让主题对象通知多个观察者。设计模式的恰当运用能增强代码可维护性。
81 0