资讯专栏INFORMATION COLUMN

优化你的执行队列-组合模式

fish / 1392人阅读

摘要:如果把设计模式当做一门语言的话,我觉得组合模式就是里面的数组,或者更确切的说,应该算是一棵树。给向上的绑定向上的执行程序可以看出,使用组合模式命令模式可以完美的打出个两个王的终极炸弹。将同类操作同目的操作放在一组。

如果把设计模式当做一门语言的话,我觉得组合模式就是里面的数组,或者更确切的说,应该算是一棵树。 树的枝干就是其他模式的使用,比如命令模式,代理模式,单例模式等等。总的来说,组合模式在这里就相当于一个容器,但也并非仅仅是个容器(不然,我还给他冠名"模式").

组合模式+命令模式

上篇的命令模式大家应该可以了解到,一个命令和命令执行者的相关系数为 zero . 所以你对命令的执行者做什么都不要紧,但是他的接口必须保持一致。 而这个特性映射出一个道理,就是既然我可以do anything, 意味着我可以在执行者上面加上其他的执行者.
are u ok?
恩恩,I"m fine, fuck u.
当然,这时候这个执行者就不叫做命令,而应该改口叫做宏。来,和上一篇一样,说球的问题。

//当点击一个球后,让球往上走,再往右走
var setCommand = function(ele, command) {
    ele.onclick = function() {
        command.exe();
    }
}
var locat = (function() { //执行事件类
    var ball = getEle("#pic"),
        style = ball.style; //缓存style
    var move = function(direct) {
        return function() {
            var dir;
            switch (direct) {
                case "bottom":
                    dir = parseInt(getLocat(ball).top) || 0;
                    style.top = `${dir+10}px`;
                    break;
                case "right":
                    dir = parseInt(getLocat(ball).left) || 0;
                    style.left = `${dir+10}px`;
                    break;
                default:
                    dir = parseInt(getLocat(ball)[direct]) || 0;
                    style[direct] = `${dir-10}px`;
            }
        }
    }
    return {
        moveUp: move("top"),
        moveDown: move("bottom"),
        moveLeft: move("left"),
        moveRight: move("right")
    }
})();
//封装命令
var moveUR = (function(){
    var exe = function(){
        locat.moveUp();
        locat.moveRight();
    }
    return  {  //封装命令
        exe
    }
})();
setCommand(getEle("leftUpBtn"), moveUR); //绑定执行效果的程序

可以看出,上面的代码可以完成基本任务。但是,如果某一天你的leader要求,让小球 上->右->下->左 进行一个循环回到原始的位置,恐怕你的反应不是很强烈。就是在moveUR里面再加些东西呗。呵呵,来,你leader又说了。在上->右->下的时候转个圈然后->左.(Ps: 转个毛线啊~~~~), 表示听到这里,想想某天你的leader抽风了,又换一个实现方式。 我想,你年都过不好~。
所以,为了让你早些回家,早点见爹妈,早点领年终奖,早点买春运火车票~
我相信,命令模式是你不二之选.
我们使用命令模式重构一下.

//上面部分不动,只将下面部分改写
//命令集合
var command = function(){
    var lists = [];
    return {
        add(command){
            lists.push(command);
        },
        exe(){
            for(var i = 0,command;command = lists[i++];){
                command.exe();
            }
        }
    }
}
//封装命令
var moveUp = (function(){
    var exe = function(){
        locat.moveUp();
    }
    return {
        exe
    }
})();
var moveLeft = (function(){
    var exe = function(){
        locat.moveLeft();
    }
    return{
        exe
    }
})();
var moveGroup1 = command();  //得到一个命令集
moveGroup1.add(moveUp);  //添加向上的命令
moveGroup1.add(moveLeft);  //。。。。
setCommand(getEle("leftUpBtn"), moveGroup1); //给向上的button,绑定向上的执行程序

可以看出,使用组合模式+命令模式可以完美的打出4个2+两个王的终极炸弹。 你可以随机的添加你想要的效果,但是前提还是必须保证有一致的接口内容。
现在可以看出组合模式的好处了吧。 想想,这个模式的特点--队列。没错,组合模式会创建一棵树,而这棵树的枝干全部是有你来添加,你可以让他变成百年梧桐,也可以让他变成行道树,而且调用的方式极其简单,使用一个接口,这棵树会把你的命令通过茎,一个接一个的输送过去。

talk is cheap, show u code

var moveUP = (function(){
    var exe = funciton(){
        conosle.log("moveUP");
    }
    return {
        exe
    }
})();
var moveLeft = (function(){
    var exe = funciton(){
        conosle.log("moveLeft");
    }
    return {
        exe
    }
})();
var moveBottom = (function(){
    var exe = funciton(){
        conosle.log("moveBottom");
    }
    return {
        exe
    }
})();
var moveRight = (function(){
    var exe = funciton(){
        conosle.log("moveRight");
    }
    return {
        exe
    }
})();
//加一点难度,对命令进行分组
var moveGrop1 = command();
moveGrop1.add(moveUp);   //moveUp
moveGrop1.add(moveLeft);  //moveLeft
var moveGrop2 = command();
moveGrop2.add(moveBottom);  //moveBottom
moveGrop2.add(moveRight);  //moveRight
var moveGrop3 = command();
moveGrop3.add(moveBottom);  //moveBottom
moveGrop3.add(moveBottom);  //moveBottom
var moveGrop = command();
moveGrop.add(moveGrop1); 
moveGrop.add(moveGrop2);
moveGrop.add(moveGrop3);
moveGrop.exe();  //接下来会按上面的顺序一个一个的运行。

可以看出,组合模式最大的一个特点就是分组操作。将同类操作(同目的操作)放在一组。 就像做一个gif了,一个帧+一个帧+一个帧... 比如,我可以蹲下来,然后起跳。 我又可以蹲下来,然后站立,走路。 就可以把一个片段,一个片段组合成你最想要的效果(怀念高中时候没有好好学习排列组合 :(] 而且重用性也是杠杠的。
可以看出,上面的add这样写好蠢。。。 为了满足装逼的需求,决定优化一下。

//命令集合
var command = function(){
  var lists = [];
    return {
        add(){
            for(var i = 0,command; command = arguments[i++];){
                lists.push(command);
            }
          console.log(lists);
        },
        exe(){
            for(var i = 0,command;command = lists[i++];){
                command.exe();
            }
        }
    }
}
//添加命令
var moveGrop1 = command();
moveGrop1.add(moveUp,moveLeft);   //moveUp,moveLeft
var moveGrop2 = command();
moveGrop2.add(moveBottom,moveRight);  //moveBottom,moveRight
var moveGrop3 = command();
moveGrop3.add(moveBottom,moveBottom);  //moveBottom,moveBottom
var moveGrop = command();
moveGrop.add(moveGrop1,moveGrop2,moveGrop3); 
moveGrop.exe();  //接下来会按上面的顺序一个一个的运行。

干净,漂亮,美美的.
但是,世上没有完美的代码,命令模式来扩展宏命令,这个是他的剑,也是他的死穴。 这样会造成,你的根节点和子节点(不可扩展的节点)之间层次的不分明。所以,一般,我们会在子节点上面加上说明,防止意外添加而导致的出错,不然,bug一出,春运票你也别想买了。
举个栗子:

var moveGrop = command();
moveGrop1.add(moveUP);
moveUP.add(moveLeft);

虽然看上去这段代码很蠢,但事实上,我确实踩过===我也很蠢xxx... 所以,这里希望警戒大家,希望把这个错误的发生率降到 0.000000001%.吧。
当然,一个艺术家,往往会给自己留一手。

var moveUp = (function(){
    var exe = funciton(){
        conosle.log("moveUp");
    }
    var add = function(){
        throw "你很蠢,不,你真的很蠢."
    }
    return {
        exe,add
    }
})();

这样,万一哪天,真的蠢了,好歹也知道自己怎么蠢的。自己知道自己蠢就可以了,记得代码写完后,把这段给删了(红脸).

组合模式注意tips

组合模式虽然很strong.但是有些概念性问题,我们还是必须分清楚.

组合模式里,根节点和子节点并不是父子关系。即,他们之间,并不存在继承关系。只是他们接口名一致而已。

字节点对象必须是同类的,这里说说的同类是指完成同一个目的相互协作的。如果将另外一个组的子节点插进来,造成的结果就是over.

尽量给根节点和子节点取望文生义的名字,后面最好标注他们的属性(根,子).

组合模式的其他用处

这个用处出自于< AlloyTeam的曾探>.(一枚我超级崇拜的大神)
组合模式的特点是子对象地位平等,特别符合我们所说的文件扫描功能。 即,文件扫描只需要知道你的文件名,以及所处的位置即可。
这里我们可以把文件比作子节点,文件夹比作父节点.

var folder = function(name){
    return {
        name,  //文件夹名
        files:[],
        add(){
            for(var i = 0,file;file = arguments[i++];){
                file.parent = this;
                this.files.push(file);
            }
        },
        scan(){  //扫描文件
            for(var file of this.files){
                console.log(file.name);  
            }
        },
        remove(){
            if(!this.parent){
                alert("该文件是更目录,不能删除!");
                return;
            }
            for(var files = this.parent.files,len = files.length-1;len>=0;len--){  //倒叙遍历文件夹
                var file = files[len];
                if(file === this){
                    files.splice(len,1);  //删除文件
                    break;
                }
            }
        }
    }
}
var file = function(name){
    return {
        name,
        scan(){
            console.log(`this is ${name}`);
        },
        remove(){
             if(!this.parent){
                alert("该文件是更目录,不能删除!");
                return;
            }
            for(var files = this.parent.files,len = files.length-1;len>=0;len--){  //倒叙遍历文件夹
                var file = files[len];
                if(file === this){

                    files.splice(len,1);  //删除文件
                    break;
                }
            }
        },
        add(){
            throw "你很蠢,不,你真的很蠢!"
        }
    }
}
var jimmyFolder = folder("jimmy");
var avi1 = file("小泽玛利亚.avi");
var avi2 = file("上野真知子.avi");
jimmyFolder.add(avi1,avi2);
jimmyFolder.scan();  //小泽玛利亚.avi , 上野真知子.avi
avi1.remove();
jimmyFolder.scan();  //上野真知子.avis

恩,get(工口).
当然,这只是一个比较简单的例子,随着你对根节点的不断操作,后面遇到的问题,肯定会凸显出来,要知道,这样,组合模式里面的节点保存是非常耗内存的,所以这个模式肯定还有很多可以优化的地方.
最后,还是那句话,不要为了模式而模式。 对于模式而言还是希望先写,后添加。
ending~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78505.html

相关文章

  • 金三银四背后,一个 Android 程序员的面试心得

    摘要:到十二月份,公司开始第二波裁员,我决定主动拿赔偿走人。加一个小插曲上面的题是饿了吗面试问到的。想去的公司没有面试好,不要气馁,继续加油准备。避免打击自信心。 回顾一下自己这段时间的经历,九月份的时候,公司通知了裁员,我匆匆忙忙地出去面了几家,但最终都没有拿到offer,我感觉今年的寒冬有点冷。到十二月份,公司开始第二波裁员,我决定主动拿赔偿走人。后续的面试过程我做了一些准备,基本都能走...

    Achilles 评论0 收藏0
  • 如何让你的JavaScript代码更加语义化

    摘要:二提高代码语义性针对上述三个案例,用更加语义化的方式来呈现代码语义化变量类型判断我觉得不需要太多的解释,对比显得清新多了吧。 语义化这个词在 HTML 中用的比较多,即根据内容的结构化选择合适的标签。其作用不容小觑: 赋予标签含义,让代码结构更加清晰,虽然我们可以在标签上添加 class 来标识,但这种通过属性来表示本体的形式会显得不够直接,而且在一定程度上也有冗余。 优化搜索引擎...

    Jaden 评论0 收藏0
  • 精读《Scheduling in React》

    摘要:调度系统,支持不同渲染优先级,对进行调度。调度带来的限制调度系统也存在两个问题。调度系统能力有限,只能在浏览器提供的能力范围内进行调度,而无法影响比如的渲染回收周期。精读关于调度系统的剖析,可以读深入剖析这篇文章,感谢我们团队的淡苍提供。 1. 引言 这次介绍的文章是 scheduling-in-react,简单来说就是 React 的调度系统,为了得到更顺滑的用户体验。 毕竟前端做到...

    LeexMuller 评论0 收藏0
  • Java面试 32个核心必考点完全解析

    摘要:如问到是否使用某框架,实际是是问该框架的使用场景,有什么特点,和同类可框架对比一系列的问题。这两个方向的区分点在于工作方向的侧重点不同。 [TOC] 这是一份来自哔哩哔哩的Java面试Java面试 32个核心必考点完全解析(完) 课程预习 1.1 课程内容分为三个模块 基础模块: 技术岗位与面试 计算机基础 JVM原理 多线程 设计模式 数据结构与算法 应用模块: 常用工具集 ...

    JiaXinYi 评论0 收藏0

发表评论

0条评论

fish

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<