9

本回内容介绍

上一回聊到工厂模式,略抽象。
介一回,咱聊门面模式就比较容易了,门面模式也叫外观模式(facade)。
官方说法,门面模式是指提供一个统一的接口去访问多个子系统的多个不同的接口,为子系统中的一组接口提供一个统一的高层接口。使得子系统更容易使用。
说白了,就是解耦类的接口。初次听到这词儿的童鞋看到代码后估计会有亲切感,开始咯:

1. 门面模式

随便想个玩意儿吧,比如一个考勤系统,一个哥们儿上班打卡,就简单模拟实现下,敲代码咯:

// 定义一个接口,还记得吧,不记得就看第五回
var PersonInterface = new Interface("PersonInterface",["getInfo"]);

// 这里简单点,就定义一个人的类
var Person = function(name){
    this.name = name;
    this.getInfo = function(){
        return "名字:"+this.name;
    }

    // 验证实现接口
    Interface.ensureImplements(this,PersonInterface);
}

// 定义考勤系统接口
var AttendSystemInterface = new Interface("attendSystemInterface",["records"]);
// 考勤系统
var AttendSystem = function(){
    this.attendTime = new Date().toLocaleString();
    this.records = function(){
        return "签到时间:"+this.attendTime;
    }
    // 验证实现接口
    Interface.ensureImplements(this,AttendSystemInterface);
}


// 这里就是个简单的门面客户端,怎么实现都在这完成
function facade(person,attendSystem){
    var res = person.getInfo()+"------"+attendSystem.records();
    alert(res);
}

// 简单的测试一下
var fox = new Person("飞狐");
var as = new AttendSystem();
facade(fox,as);    //名字:飞狐------签到时间:2015/11/18 下午18:08:08 

这就是简单门面模式的模拟了,比较好理解,很多网上的资料都用JS的DOM2事件例子来讲的门面模式,走走过场来一个好了,看下一个例子,走你...

2. 门面模式之DOM2事件

在DOM2级事件中的两个方法(注:W3C,IE8及之前的浏览器不支持):
addEventListener(),removeEventListener()
所有DOM 节点中都包含这两个方法,并且都接受3个参数:事件名,函数,冒泡或捕获的布尔值(true 表示捕获,false 表示冒泡);
在IE中实现了类似的方法:attachEvent() 和 detachEvent(),这两个方法接受相同的参数:事件名称和函数。

var EventUtil = {
    // 添加事件
    addHandler: function(el,type,fn){
        if(el.addEventListener){
            // W3C
            el.addEventListener(type,fn,false);
        }else if(el.attachEvent){
            // IE
            el.attachEvent("on"+type,fn);
        }else{
            el["on"+type] = fn;
        }
    },
    // 移除事件
    removeHandler: function(el,type,fn){
        if(el.removeEventListener){
            // W3C
            el.removeEventListener(type,fn,false);
        }else if(el.detachEvent){
            // IE
            el.detachEvent("on"+type,fn);
        }else{
            el["on"+type] = fn;
        }
    },
    /*
     * 获取事件,这里注意一下IE方式( window.event )获取事件对象,
     * 但是在Firefox中会报错,提示:window.event is undefined,
     * 说明Firefox不支持IE方式获取事件对象而是以句柄的第一个参数传入的
     */ 
    getEvent:function(event){
        return event?event:window.event;
    },
    /*
     * 获取事件作用的元素
     * IE:有srcElement属性,没有target属性。
     * firefox:有target属性,没有srcElement属性。
     */ 
    getTarget:function(event){
        return event.target||event.srcElement;
    },
    // 取消事件的默认动作
    preventDefault:function(event){
        if(event.preventDefault){
            event.preventDefault();
        }else{    // IE阻止默认行为
            event.returnValue = false;
        }
    },
    // 取消冒泡
    stopPropagation:function(event){
        // W3C的取消冒泡
        if(event.stopPropagation){
            event.stopPropagation();
        }else{    // IE的取消冒泡
            event.cancelBubble = true;
        }
    }

};

document.write("<button id='btn'>给飞狐点个赞</button>");
var btn = document.getElementById("btn");
EventUtil.addHandler(btn,"click",function(){
    alert("Are you ok!");
}); 

这个例子特简单吧,是否有似曾相识的感觉,是的,这是模拟高程3上事件的例子,这里对事件封装得很简单,而在IE中还有这几个区别:
IE 不支持捕获,只支持冒泡;
IE 添加事件不能屏蔽重复的函数;
IE 中的 this 指向的是 window 而不是 DOM 对象;
IE 无法接受 event 对象,但使用了 attachEvent()却可以,只是有区别;
我们这里只是聊门面模式,简单的模拟,JS的事件系统有很多可以细细品味的地方,以后聊到ExtJS事件系统源码的时候还会详细的刨根问底,好像又扯多了...

装逼图
又到装逼时候了。双11的价格挺诱人吧,我是没忍住买了一个本本,尼玛同款电脑,天猫比京东便宜860块吖~~

这一回聊的内容少,难度很小,比较好理解。
下面的内容很简单,聊一下JS的事件委托...

JS事件委托

高程3上对事件委托的描述是,事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。接着刚刚封装的事件例子,继续写:

<ul id="ul">
  <li>飞狐</li>
  <li>帅狐</li>
  <li>飞狐就是帅</li>
</ul>
// 获取id
function $(id){
    return document.getElementById(id);
}
var oUl = $('ul');
var oLi = oUl.getElementsByTagName("li");

// 不用事件委托,就得循环每个子li,分别绑定事件
for(var i=0,len=oLi.length;i<len;i++){
    // 添加事件
    EventUtil.addHandler(oLi[i],'click',function(e){
        // 获取事件
        e = EventUtil.getEvent(e);
        // 获取事件作用的元素
        var tag = EventUtil.getTarget(e);
        alert(tag.innerHTML);
    })
}

// 用事件委托来写,只需要在Ul上添加一个事件
EventUtil.addHandler(oUl,'click',function(e){
    e = EventUtil.getEvent(e);
    var tag = EventUtil.getTarget(e);
    alert(tag.innerHTML);
})

这个是拿书上的例子来改的,目的是为了让大家更方便的理解,可以看出事件委托占用内存少,读取速度快,性能更高。

这一回,主要聊了门面模式,DOM2级事件,事件委托,难度比较小~~
下一回,聊聊代理模式,也比较简单。

客观看完点个赞,推荐推荐呗,嘿嘿~~


注:此系飞狐原创,转载请注明出处


飞狐
2.4k 声望1.4k 粉丝

专注AI量化,技术界最懂金融的CFA金融分析师