学习
实践
活动
工具
TVP
写文章
专栏首页AlbertYang的编程之路设计模式(12)[JS版]--JavaScript必会设计模式之外观模式(Façade Pattern)

设计模式(12)[JS版]--JavaScript必会设计模式之外观模式(Façade Pattern)

1 什么是外观模式

外观模式为子系统提供了一个接口,它屏蔽一个或多个子系统的复杂功,提供了一个一致的界面(接口)给用户。外观模式是一个非常简单的模式,但它的功能却很很强大,非常有用。外观模式不仅简化类中的接口,而且对接口与调用者也进行了解耦。外观模式可以将一些复杂操作封装起来,并创建一个简单的接囗用于调用,它经常出现在多层架构的系统中。

外观模式的目的是提供一个高级接口(属性和方法),使子系统或工具箱更易于客户端使用。在多层网络应用中,经常有一个表现层,它是服务层的客户端。这两个层之间的通信是通过一个定义良好的API来实现的。这个API,或者说Façade,将复杂的业务对象和它们的交互隐藏在表现层之外。

另一个使用Façades的领域是在代码的重构中。假设你正在维护一个比较老的系统,里面有一些容易令人困惑或混乱的代码,而客户端不应该关注这些混乱的代码,你可以将这些代码隐藏在Façade后面,Façade只暴露出必要的东西,并呈现出一个更干净和易于使用的界面。外观模式经常与其他设计模式结合使用,外观模式本身经常用来实现单人工厂模式。

2 外观模式的主要的参与者

参与该模式的对象有

门面 (Facade ):

1 知道哪些子系统负责处理请求。

2 将客户的请求委托给相应的子系统对象。 子系统(Sub Systems) :

1 实现和执行专门的子系统功能。

2 对门面一无所知,也没有参照物。

3 代码实现

在下面的JavaScript中的示例代码中,Mortgage对象是示例代码中的Facade。它向客户端提供了一个简单的接口,只有一个方法:applyFor(),但在这个简单的API下面隐藏着相当复杂的操作。

申请人申请贷款,申请人的名字被传递到Mortgage构造函数中,之后调用applyFor方法,并输入申请的贷款金额。在内部,这个方法使用了来自3个独立的子系统的服务,这些子系统很复杂,可能需要一些时间来处理,它们是银行、信用和背景。根据这几个标准(银行账单、信用报告和犯罪背景等),判断是否接受申请人的贷款请求。

<!DOCTYPE html>
<html>
        <head>
                <meta charset="utf-8">
                <title>外观模式:公众号AlbertYang</title>
        </head>
        <body>
        </body>
        <script>
                //抵押贷款
                var Mortgage = function(name) {
                        this.name = name;
                }

                Mortgage.prototype = {
                        //申请贷款
                        applyFor: function(amount) {
                                // 访问多个子系统
                                var result = "批准";
                                if (!new Bank().verify(this.name, amount)) {
                                        result = "拒绝";
                                } else if (!new Credit().get(this.name)) {
                                        result = "拒绝";
                                } else if (!new Background().check(this.name)) {
                                        result = "拒绝";
                                }
                                return this.name + "你的" + amount + " 抵押贷款,已经被" + result;
                        }
                }
                //银行
                var Bank = function() {
                        this.verify = function(name, amount) {
                                // 省略复杂的逻辑代码......
                                return true;
                        }
                }
                //信用
                var Credit = function() {
                        this.get = function(name) {
                                // 省略复杂的逻辑代码......
                                return true;
                        }
                }
                //背景资料
                var Background = function() {
                        this.check = function(name) {
                                // 省略复杂的逻辑代码......
                                return true;
                        }
                }

                function run() {
                        var mortgage = new Mortgage("张三");
                        var result = mortgage.applyFor("100,000元");

                        console.info("%c%s", "color:red; font-size:18px", result);
                }
                run();
</script>
</html>

4 实例应用

4.1 跨浏览器事件

在下面的代码中,我们使用了外观模式通过检测浏览器特性,创建一个跨浏览器的事件监听方法,下面的例子是对input对象添加click事件。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>跨浏览器事件方法:公众号AlbertYang</title>
  </head>
  <body>
    <input type="button" id="myInput" value="提交" />
  </body>
  <script>
    function addEvent(dom, type, fn) {
      if (dom.addEventListener) { // 支持DOM2级事件处理方法的浏览器
        dom.addEventListener(type, fn, false)
      } else if (dom.attachEvent) { // 不支持DOM2级但支持attachEvent
        dom.attachEvent('on' + type, fn)
      } else {
        dom['on' + type] = fn // 都不支持的浏览器
      }
    }

    const myInput = document.getElementById('myInput')
    addEvent(myInput, 'click', function() {
      console.log('绑定 click 事件')
    })
</script>
</html>

4.2 阻止默认和冒泡事件

下面的例子,把阻止冒泡和阻止默认事件放到了外观角色中,其中的stopEvent就是提供给使用者,用来阻止冒泡和默认事件的一个方法。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>阻止默认和冒泡事件:公众号AlbertYang</title>
  </head>
  <body>
    <input type="button" id="myInput" value="提交" />
  </body>
  <script>
    var N = window.N || {};

    N.tools = {
      cancelBubble: function(e) { //取消冒泡
        if (e.stopPropagation) {
          e.stopPropagation();
        } else {
          e.cancelBubble = true; // IE下
        }
      },
      preventDefault: function(e) { // 阻止默认事件
        if (e.preventDefault) {
          e.preventDefault();
        } else {
          e.returnValue = false; // IE下
        }
      },
      stopEvent: function(e) {
        N.tools.cancelBubble(e);
        N.tools.preventDefault(e);
      }
    }

    document.onclick = function(e) {
      console.log('哈哈')
    }

    document.getElementById('myInput').onclick = function(e) {
      N.tools.stopEvent(e)
      console.log('呵呵')
    }
</script>
</html>

5 总结

外观模式在javascript的应用广泛,如果某块代码反复出现,比如函数a的调用基本都出现在函数b的调用之前,那么可以考虑考虑将这块代码使用外观角色包装一下来优化结构。另外对于一些浏览器不兼容的API,最好的方式便是将跨浏览器差异全部集中放置到一个外观模式实例中来提供一个对外接口。另外在软件设计初期,我们应该有意识地将不同的两个层分离,比如经典的三层结构,而在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,增加外观模式可以提供一个简单的接口,减少它们之间的依赖。如果我们正在维护一个遗留的大型系统,我们应该为该系统开发一个外观模式类,给以前设计粗糙和高度复杂的遗留代码提供比较清晰的接口,让新系统和外观对象进行交互。外观模式被开发者连续使用时会产生一定的性能问题,因为在每次调用时都要检测功能的可用性。

今天的学习就到这里,你可以使用今天学习的技巧来改善一下你曾经的代码,如果想继续提高,欢迎关注我,每天学习进步一点点,就是领先的开始。

文章分享自微信公众号:
AlbertYang

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:AlbertYang
原始发表时间:2020-08-07
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 前端的设计模式系列-外观(门面)模式

    代码也写了几年了,设计模式处于看了忘,忘了看的状态,最近对设计模式有了点感觉,索性就再学习总结下吧。

    windliang
  • C++设计模式笔记(03-01) - Template Method_模板方法(上)

    [1]: 《Design Patterns: Elements of Reusable Object-Oriented Software》(即后述《设计模式:可...

    Fista
  • 初探Java设计模式4:JDK中的设计模式

    本文主要是归纳了JDK中所包含的设计模式,包括作用和其设计类图。 首先来个总结,具体的某个模式可以一个一个慢慢写,希望能对研究JDK和设计模式有所帮助。 一、...

    公众号_程序员黄小斜
  • 设计模式(0)—— 概述

    设计模式(Design Pattern),是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

    阳光岛主
  • Web前端开发推荐阅读书籍、学习课程下载

    学校里没有前端的课程,那如何学习JavaScript,又如何使自己成为一个合格的前端工程师呢?

    慕白
  • 《JavaScript设计模式》初次笔记——wsdchong[通俗易懂]

    设计模式一直久仰大名,但是没有去花时间去了解,于是今天特意花时间去看《JavaScript设计模式》(2013年6月出版)和w3cschool上的设计模式。然后...

    全栈程序员站长
  • JS 原型模式

    原型模式(Prototype pattern),用原型实例指向创建对象的类,使用于创建新的对象的类的共享原型的属性与方法。

    前端下午茶
  • 前端学习与工作书籍推荐

    前端_AWhile
  • 打开API网关设计的一扇窗

    摘要 API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。 ? ...

    IT大咖说
  • 《你不知道的JavaScript》:拎清原型继承的原理

    虽然在js中没有类,构造函数本质上也只是一个普通函数,new关键字调用一个构造函数来创建一个新对象,也是js在努力模仿面向对象语言中类new对象的实现,这个模仿...

    前端_AWhile
  • 由浅入深,66条JavaScript面试知识点

    来源:https://juejin.im/post/5ef8377f6fb9a07e693a6061

    刘小夕
  • 由浅入深,66条JavaScript面试知识点

    来源:https://juejin.im/post/5ef8377f6fb9a07e693a6061

    zz_jesse
  • 使用JavaScript学习设计模式

    之后紧接着买了这本JavaScript 设计模式核⼼原理与应⽤实践,刚好最近有小册免费学的活动,就赶紧把这篇笔记整理出来了,并且补充了小册子中的没有写到的其余设...

    九旬
  • 切图仔最后的倔强:包教不包会设计模式 - 结构型

    当我们将系统分成多个子系统时,我们会降低代码复杂性。编程时的最佳实践是最小化子系统之间的通信和依赖关系。实现这一目标的一个好方法是引入一个facade对象,为子...

    前端劝退师
  • 由浅入深,66条JavaScript面试知识点

    来源:https://juejin.im/post/5ef8377f6fb9a07e693a6061

    winty
  • iOS常用设计模式

    适配器模式将一个类的接口适配成用户所期待的。一个适配器通常允许因为接口不兼容而不能一起工作的类能够在一起工作,做法是将类自己的接口包裹在一个已存在的类中。

    赵哥窟
  • 外观模式

    外观模式Facade Pattern又称为门面模式,它是一种对象结构型模式,外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一...

    WindrunnerMax
  • 前端需要了解的9种设计模式 什么是设计模式?设计模式的类型一. 结构型模式(Structural Patterns)二. 创建型模式(Creat

    设计模式是对软件设计开发过程中反复出现的某类问题的通用解决方案。设计模式更多的是指导思想和方法论,而不是现成的代码,当然每种设计模式都有每种语言中的具体实现方式...

    MudOnTire

扫码关注腾讯云开发者

领取腾讯云代金券