焖面&适配器

门面情势

"焖面",有两个作用,一是简化类的接口;二是消弭类与运用他的营业代码之间的耦合.他几乎是一切 JS 库的中心准绳.经由过程竖立一些轻易要领能够让复杂体系变得越发简朴易用,焖面情势能够使库供应的东西越发轻易明白.

焖面能够简化毛病纪录也许跟踪页面视图统计数据这类这类常常使用,重复性的使命,经由过程增加一些要领(是对元有一些要领的组合运用),还能够让对象的功用更完美.
焖面能够简化复杂接口,能够在背地为你举行毛病搜检,消灭不再须要的大对象,以及用一种简朴体式格局展示对象功用.
这是一种组织性的情势,能够用来修正类和对象的接口,使其更容易运用.

罕见的焖面元素

快捷体式格局图标,是在指导用户至某个处所的接口,假如没有快捷体式格局,那些内部深层次的文件也许目次就不太轻易查找.
基于 GUI 的 OS 就是计算机数据和功用的一个焖面.每次点击,拖动也许挪动东西,实际上是在操纵焖面,间接地实行一些背地的敕令.
这里有个兼容种种浏览器的事宜监听器例子(之前桥接也有个事宜监听器例子,然则如今要触及 addEvent()函数的定义:

function addEvent(el, type, fn) {
    if (window.addEventListener) {
        el.addEVentListrner(type, fn, false);
    }
    else if (window.attachEvent) {
        el.attachEvent(on + type, fn);
    }
    else {
        el['on' + type] = fn;
    }
}

JS 是一种事宜驱动的言语,addEvent 函数是一个基础的焖面,每次为一个元素增加事宜监听器时都得针对浏览器间的差异举行搜检而懊恼.

为了只管进步开辟效力,简化罕见使命,供应兼容每一个浏览器各自内置 JS 函数完成的配合接口(如许就会轻易很多),诞生了许很多多东西函数集(比如说 loadash),另有Prototype, jQuery, YUI, Vue, React, Angular 等等第三方 JS 库.

焖面的一个优点是对函数的组合–convenience function:

function a(x) {
    ...
}
function b(y) {
    ...
}
function ab(x, y) {
    a(x);
    b(y);
}

之所以依旧保存前两个函数,是出于细粒度和灵活性的斟酌.

看起来有点相似于桥接情势连接多个类…不过不能殽杂,这里的焖面仅仅是对函数的组合,没有触及到类.
用 DOM 剧本编程经常常使用到的两个一般事宜要领为例:

event.stopPropagation()
event.preventDefault()

前者用来中缀事宜沿着 DOM 树向上冒泡流传,后者是阻挠浏览器针对一个事宜的默许行动.比如说防备浏览器链接点击跳转新页面,还能够用来阻挠表单的提交.
差异浏览器为这两个功用供应的接口略有差异,所以:

var DED = window.DED || {};
DED.util = {
    stopPropagation: function (e) {
        if (ev.stopPropagation) {
            // W3 interface
            e.stopPropagation();
        }
        else {
            // IE's interface
            e.cancelBubble = true;
        }
    },
    preventDefault: function (e) {
        if (e.preventDefault) {
            // W3 interface
            e.preventDefault();
        }
        else {
            // IE's interface
            e.returnValue = false;
        }
    },

    // our convience method.
    stopEvent: function (e) {
        DED.util.stopPropagation(e);
        DED.util.preventDefault(e);
    }

}

焖面和适配器看起来很像,然则实际上,适配器是一种包装器,对接口举行适配以便在不兼容体系中运用它,而建立焖面元素主如果轻易起见,供应一个简化的接口,并不适合于须要特定接口的体系.

设置 HTML 元素款式

如今要用原生 js一次设置几个元素的某个款式,很合理:

var ele1 = document.getElementById('foo');
ele1.style.color = '#f00';

var ele2 = document.getElementById('foo');
ele2.style.color = '#f00';

var ele3 = document.getElementById('foo');
ele3.style.color = '#f00';

不停地写 getElementById 而且为每一个元素设置一样的属性和数值一定就不对,这时刻用上焖面,建立一个接口,简化成批设置元素款式的事情.如今我们逆向头脑:先设想一下如何最轻易地运用该要领,然后再编写要领源码自身:

setCSS(['foo'], {
    position: 'absolute',
    top: '50px',
    left: '300px'
});

function serCSS(el, styles) {
    for (var prop in styles) {
        if (el.hasOwnProperty(prop)) continue;
        setStyle(el, prop, styles[prop]);
    }
}

设想一个事宜东西

在处置惩罚浏览器的开辟题目时,最好建立一些焖面函数,假如要设想一个大型库,最好把个中一切的东西元素拢在一同,如许更好用,接见起来也简朴.鉴于种种浏览器在事宜处置惩罚方面表现出来的大批差异,开辟一个事宜东西很有必要.
要用到单体情势,位于DED.Util 定名空间中,包括着各个静态要领,比如说,如何取得事宜目标元素和事宜对象,另有如何处置惩罚事宜流传和事宜默许行动:

DED.Util.Event = {
    getEvent: function (e) {
        return e || window.event;
    },
    getTarget: function (e) {
        return e.target || e.srcElement;
    },
    stopPropagation: function (e) {
        if (e.stopPropagation) {
            e.stopPropagation();
        }
        else {
            e.cancelBubble = true;
        }
    },
    preventDefault: function (e) {
        if (e.preventDefault) {
            e.preventDefault();
        }
        else {
            e.returnValue = false;
        }
    },
    stopEvent: function (e) {
        this.stopPropagation(e);
        this.preventDefault(e);
    }
};

焖面情势的有用场所

推断是不是应当运用焖面情势的关键在于识别那些重复成组涌现的代码,假如两个函数常常一块涌现,那末也许能够能够斟酌写一个组合式的焖面函数;
在中心东西代码中运用焖面函数的另一个目标是应对 js 内置函数在差异浏览器中的差异表现.如许做并不是由于不能直接运用这些 API,而是由于在处置惩罚浏览器差异题目时最好的解决办法是把这些差异抽取到焖面要领中
,比如说addEvent 函数能够供应一个更一致的接口.

编写一次组合代码,然后能够重复运用,而且供应了一个处置惩罚罕见题目和使命的简化接口,也供应了较高层的功用,降低了对外部代码的依靠水平,为运用体系的开辟增加了一些分外的灵活性.经由过程运用焖面情势,能够防止与基层子体系严密耦合,能够对这个体系举行修正而不会影响到营业代码.

焖面情势常常会被滥用,比拟一个复杂的焖面函数,一个更简朴的构成函数在粒度方面更有吸引力.

适配器

它用来在现有接口和不兼容的类之间举行适配.运用这类情势的对象叫做包装器 wrapper,他们是在用一个新的接口包装另一个对象.在设想类的时刻往往会碰到有些接口不能与现有 API 一同运用的状况,借助于适配器,没必要直接修正这些类也能运用它们.如今将考核这类场所,并讨论用适配器模连接对象的种种体式格局.

适配器特性

适配器能够被增加到现有代码中以谐和两个差异的接口.假如现有代码的接口能很好地满足须要,那末能够没有必要运用适配器.然则假如现有接口关于手头的需求来讲不够直观也许有用,那末能够运用适配器来供应一个更简约也许更雄厚的接口.

从表面上看,适配器情势很想焖面情势,他们都要对别的对象举行包装而且转变其显现的接口,差异在于如何转变接口.焖面元素展示的是一个简化的接口,它并不供应分外的挑选,而且有时刻为了轻易完成罕见使命他还会做出一些假定;而适配器则要把一个接口转换另一个接口,他并不会滤除某些才能,也不会简化接口.

适配器能够被完成为不兼容要领挪用之间的一个代码薄层.假如你有一个居右3个字符串参数的函数,然则客户体系拥有的是一个包括3个字符串元素的数组,那末就能够用一个适配器来连接两者:

var clientObject = {
    string1: 'foo',
    string2: 'var',
    string3: 'baz'
};
function interfaceMedthod(str1, str2, str3) {
    ...
}

// in order to pass clientObject-param to interfaceMethod-function, we need 适配器:
function clentToInterfaceAdapter(srcObj) {
    interfaceMethod(srcObj.string1, srcObj.string2, srcObj.string3);
}

clentToInterfaceAdapter(clientObject);

clientToInterfaceAdapter 函数的作用就在于对 interfaceMethod 函数举行包装,并把通报给它的参数转换为后者须要的情势.

适配器有用场所

有用于客户体系期待接口与现有 API 供应的接口不兼容这类场所.它只能用来谐和语法上的差异题目.适配器所适配的两个要领实行的应当是相似的使命,不然的话没法解决题目.

有助于防止大规模修正现有营业代码,其事情机制:用一个新的接口对现有类的接口举行包装,如许营业代码就无需大动干戈.

假如须要完全重写代码,别的适配器也会引入一批不要支撑的新东西;
假如现有 API 还未定形也许新接口还没有定形那末适配器不会一向管用;
所以说适配器有多是一种没必要要的开支,没必要引入.

    原文作者:南赐
    原文地址: https://segmentfault.com/a/1190000007132402
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞