资讯专栏INFORMATION COLUMN

我说你做--命令模式

andong777 / 667人阅读

摘要:而且,说完起立之后,副班长也不知道谁会说老湿好。不要紧,我们可以使用命令模式来弥补这个缺陷,因为命令模式最大的一个扩展性就是命令者和命令的执行者分开了。这样可以清楚的说明命令模式的优势到底在哪里。

命令模式

望文生义,所谓的命令模式其实就是:
发出一定的指令,然后由对象接受并且执行
需要强调一点,就是对于命令的发出者来说,他并不知道该命令是给谁,执行效果是怎样,他只管发出命令就行。听到这里感觉和发布订阅者模式有异曲同工的效果。 但事实上,他们两者应用的场景还是有比较大的区分。不仅写法上有不同,而且执行的过程也有所不同。要知道在命令模式里面执行的效果是1对1,而在订阅者模式里面是1对>=1的.
你在逼逼什么?
哦,说明白一点。 就和上课一样。 老师进教室了,首先说:“上课!”. 接着,你们的monitor 会立马接上: "起立!"。 然后,你们就会异口同声的说:"老湿好~"。 没错,分析一下。 当老师说上课的时候,他并不会知道谁会说起立,比如今天班长谈恋爱去了,那副班长顶上。 而且,说完起立之后,副班长也不知道谁会说老湿好。 也就是命令的发出者,只管发出一个命令,然后你们只管执行就over了.
talk is cheap, show u code.

//事件发出者
var setCommand = function(ele,command){ //命令的绑定者
    ele.onclick = function(){
        command.do();
    }
}
//事件的执行者

var location = (function() { //执行事件类
    var ball = getEle("#ball");
    var move = function(direct) {
        return function() {
            var style = ball.style,
                dir = parseInt(style[direct]);
            style[direct] = `${dir-200}px`;
        }
    }
    var moveUp = move("top");
    var moveDown = move("down");
    var moveLeft = move("left");
    var moveRight = move("right");
    return {
        moveUp, 
        moveDown,
        moveLeft,
        moveRight
    }
})();
//封装命令
var MoveUp = function(exer){
    this.exer = exer;
}
MoveUp.prototype.do = function(){
    this.exer.moveUP();
}
var MoveDown = function(exer){
    this.exer = exer;
}
MoveDown.prototype.do = function(){
    this.exer.moveDown();
}
var MoveLeft = function(exer){
    this.exer = exer;
}
MoveLeft.prototype.do = function(){
    this.exer.moveLeft();
}
var MoveRight = function(exer){
    this.exer = exer;
}
MoveRight.prototype.do = function(){
    this.exer.moveRight();
}
setCommand(getEle("upBtn"), new MoveUp(location)); //给向上的button,绑定向上的执行程序
setCommand(getEle("downBtn"), new MoveDown(location)); //...
setCommand(getEle("leftBtn"), new MoveLeft(location)); //...
setCommand(getEle("rightBtn"), new MoveRight(location)); //....

可以清晰的看到,在命令模式中,触发事件(onclick)和执行程序(command.do())都是已知的。 但是这个执行的消息给谁,或者执行产生的效果是怎样的,在命令的发出者这一方都是未知的。需要注意的是,这时候的未知只限于命令的发出者而言。也就是现在命令模式将发出者和执行者给解耦开,即,可变的部分和不可变的部分分开。
上面逼逼这么多到底在说shenme...
其实一切原理都是枯燥的,实例才是王道。 来,我们来做个比较。也就是不使用命令模式,直接写上面的例子(偷个懒,只写moveUP部分).

var ele = getEle("#ball");
getELe(".moveUp").onclick = function(){
     var style = this.style,
        dir = parseInt(style["top"]);
        style["top"] = `${dir-200}px`;
    }
}

上面的代码同样能完成上面辣么辣么长的代码完成的效果,那为什么还要使用上面的写法呢?
艹~ 请问,你下面那段代码,能体现你的bigger吗? 能体现你是代码艺术家的feeling吗?能体现你的思维能力吗?
No NO No~
我们来分析下why.
首先下面那段代码可以完成上面的功能,但是万一有一天,一个名叫产经的生物和你说

"亲爱的,你能不能在加一个button,让这个球可以斜着走,可以转个圈呢? 哈哈,我相信你一定可以的。"

呵呵,你话都没说。 想当然这个锅,你必须背。好吧,那开始做吧。(用那个渣渣代码演示一遍).

function getY(x){
    var k = 1.2;
    return k*x;
}
getELe("#diagnoal").onclick = function(){
     var style = ele.style,
        x = parseInt(style["left"]),
        y = parseInt(style["top"]),
        style["left"] = `${x-200}px`;
        style["top"] = `${y-getY(200)}px`;
    }
}

可以想象,最后如果产经的需求不断增多,那么你在事件处理的回调会越来越复杂,比如:

"亲爱的,你斜着走都实现了,那4个方向能不能都可以走呢?"

我想这时候,你应该会懵逼了。不要紧,我们可以使用命令模式来弥补这个缺陷,因为命令模式最大的一个扩展性就是命令者和命令的执行者分开了。而且在上面面向过程的代码中,看不出什么逻辑出来,只是知道,这个click是触发什么的。 而事件回调中的代码重用性也是非常低的。
这里使用命令模式重构一遍
//其他的还是一样,这里主要将4个方向的代码重构一下

var location = (function() { //执行事件类
    var ball = getEle("#ball");
    var compMove = function(hori,vert) { //垂直和水平方向
        var k = 1.2; //移动的斜率
        var getY = function() {
            return k * x;
        }
        return function() {
            var style = ball.style,
                x = parseInt(style[hori]), //水平方向上的位置
                y = parseInt(style[vert]); //垂直方向上的位置
            style[hori] = `${x-200}px`;
            style[vert] = `${y-getY(200)}px`;  //执行移动
        }
    };
    //斜方向绑定代码
    var moveLU = compMOve("left","top"); 
    var moveRU = compMOve("right","top");
    var moveLB = compMOve("left","bottom");
    var moveRB = compMOve("right","bottom");
    return {
        moveLU
        moveRU,
        moveLB,
        moveRB
    }
})();
//封装命令
var MoveLU = function(exer) {
    this.exer = exer;
}
MoveLU.prototype.do = function() {
    this.exer.moveLU();
}   
setCommand(getEle("leftUpBtn"), new MoveLU(location)); //给向上的button,绑定向上的执行程序

可以看出来,虽然代码多,但是至少我们将改动的地方降到最低了。
setCommand这个不变,变的只是绑定click的对象和执行者。 这样可以清楚的说明命令模式的优势到底在哪里。
当然,我们还可以做一个优化,要知道,js是一门函数至上的语言,因为函数可以像参数一样被传来传去,所以可以这样改写命令的绑定者.

var setCommand  = function(ele,fn){
    ele.onclick = function(){
        fn();
    }
}
setCommand(getEle("leftUpBtn",()=>{location.moveLU()}))); //给向上的button,绑定向上的执行程序

这样就可以省去中间一大堆的事件修饰,从而将函数直接暴露使用。推荐这样写法,因为这个才是js的真正实力。
要知道一个模式的精华不是看他能怎么用,而是要看你怎么用他。

命令模式实现缓存效果

其实,缓存并不是什么高上大的东西,就是在函数里名,有一个变量来保存你的结果,而你可以遍历这个结果.

function fb(num) {
    if (num <= 1) {
        return 1;
    }
    return num * fb(--num)
}
//缓存代理出场了
var cProxy = (function() {
    var cache = {};
    return function(num) {
        if (cache[num]) {
            console.log(`this is cache ${cache[num]}`);
            return cache[num];
        }
        return cache[num] = fb(num);
    }
})();
//测试
console.log(cProxy(4)); //24
cProxy(4); //"this is cache 24"

上面是我以前写代理缓存的例子。 里面有个叫cache的东西,就是来保存你的结果(放在内存中),以备下次使用。
而命令模式的缓存有个极大的用途就是一个 撤销和重做的效果.
在上面的例子中可以保留每一个节点小球的位置(简单起见,还是以最初的上下左右为基准吧)
由于代码过长,我放在fiddle里面(里面代码可能会和上面有很大出入,但是如果理解了上面的说法的话,我相信理解起来肯定很快的)。有兴趣可以看看。是个实例demo哦。 :)
撤销实例
特此说明,由于使用原生写的里面会有写hacks,如果大家有自己独到的见解,欢迎拍砖(请轻点~). 也欢迎点个推荐呗。

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

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

相关文章

  • 一篇文章看懂大数据分析就业前景及职能定位

    摘要:今天就先给大家讲大数据分析工程师。所以你要和我说你在外面培训了个月的大数据分析后,就想做了,那请你再考虑考虑。而他们鼓吹的大数据分析师,其实就是。 showImg(https://segmentfault.com/img/remote/1460000018722710?w=1000&h=750); Overview: 序 基本概念 DS的职能要求 DE的职能要求 总结 一、序 今天...

    itvincent 评论0 收藏0
  • 程序员该如何有效的找工作?

    摘要:经验少的程序员小猿同学毕业工作一年了,在公司感觉自己的能力很好了,能力大于老板给的价值了,所以想要涨工资,但是老板给涨的不够理想,小猿听说跳槽可以让自己的工资翻倍,毅然决然的就辞职了,决定重新找工作。 又到了一周一次的周末心灵鸡汤的时间了,希望大家能够痛痛快快的喝了这碗鸡汤,让这酸爽的感觉使你永生难忘。哈哈……这周又有几个人,尤其是毕业生在「非著名程序员」微信公众号里私聊我关于找不到工...

    BLUE 评论0 收藏0
  • 蚂蚁金服实习生面经总结(已拿口头offer)

    摘要:我自己总结的学习的系统知识点以及面试问题,已经开源,目前已经。面试官那你都了解里面的哪些东西呢我哈哈哈这可是我的强项,从,说到,,又说到线程池,分别说了底层实现和项目中的应用。 我自己总结的Java学习的系统知识点以及面试问题,已经开源,目前已经 35k+ Star。会一直完善下去,欢迎建议和指导,同时也欢迎Star: https://github.com/Snailclimb... ...

    Lemon_95 评论0 收藏0

发表评论

0条评论

andong777

|高级讲师

TA的文章

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