资讯专栏INFORMATION COLUMN

焖面&适配器

suemi / 3459人阅读

摘要:门面模式焖面有两个作用一是简化类的接口二是消除类与使用他的业务代码之间的耦合他几乎是所有库的核心原则通过建立一些便利方法可以让复杂系统变得更加简单易用焖面模式可以使库提供的工具更加容易理解焖面可以简化错误记录或者跟踪页面视图统计数据这类这类

门面模式
"焖面",有两个作用,一是简化类的接口;二是消除类与使用他的业务代码之间的耦合.他几乎是所有 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://www.ucloud.cn/yun/87966.html

相关文章

  • 对象存储 性能数据与分析 US3

    摘要:缺陷虽然目前确实能给基于存储的大数据方案带来进一步性能提高,但目前的设计还是有不少缺陷,主要在体现在几个方面单点架构使得可靠性降低。性能数据与分析本篇目录测试环境测试数据us3vmds基于Go语言开发,自带了Go的profile功能,通过以下命令,可以在指定地址开启Go的运行时性能分析HTTP服务:➜ bin ✗ us3vmds pprof --open 127.0.0.1 8081 ➜ ...

    ernest.wang 评论0 收藏140
  • python设计模式-外观模式

    摘要:上一篇设计模式适配器模式介绍了如何将一个类的接口转换成另一个符合期望的接口。这一篇将要介绍需要一个为了简化接口而改变接口的新模式外观模式。 上一篇《python设计模式-适配器模式》介绍了如何将一个类的接口转换成另一个符合期望的接口。这一篇将要介绍需要一个为了简化接口而改变接口的新模式-外观模式(Facade-Pattern)。 问题 问题:如果你组装了一套家庭影院,内含播放器、投影...

    vincent_xyb 评论0 收藏0
  • 开发之路(设计模式八:外观模式)

    摘要:改变接口的新模式,为了简化接口这次带来的模式为外观模式,之所以这么称呼,因为它将一个或多个类复杂的一切都隐藏起来。 改变接口的新模式,为了简化接口 这次带来的模式为外观模式,之所以这么称呼,因为它将一个或多个类复杂的一切都隐藏起来。 我依旧举生活中例子,现在有些朋友家的液晶电视可能是大尺寸的,或者有用投影仪来看电视,打游戏的。有一天我想用家庭影院系统在家里看一次大片。 ...

    hosition 评论0 收藏0
  • the-clean-architecture

    过去几年,我们已经看到了一系列关于系统架构的想法,包括:六边形架构(接口与适配器)洋葱架构(Onion Architecture)Screaming ArchitectureDCIBCE这些架构有很多共同的点(思想),尽管它们细节上有所不区别,它们都有相同的目标,那就是关注点分离(the speration of concerns), 它们都是通过将软件分层来实现这种分离,每个组件至少有一个用于业...

    社区管理员 评论0 收藏0

发表评论

0条评论

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