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

目录

1 什么是外观模式

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

3 代码实现

4 实例应用

4.1 跨浏览器事件

4.2 阻止默认和冒泡事件

5 总结


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,最好的方式便是将跨浏览器差异全部集中放置到一个外观模式实例中来提供一个对外接口。另外在软件设计初期,我们应该有意识地将不同的两个层分离,比如经典的三层结构,而在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,增加外观模式可以提供一个简单的接口,减少它们之间的依赖。 如果我们正在维护一个遗留的大型系统,我们应该为该系统开发一个外观模式类,给以前设计粗糙和高度复杂的遗留代码提供比较清晰的接口,让新系统和外观对象进行交互。外观模式被开发者连续使用时会产生一定的性能问题,因为在每次调用时都要检测功能的可用性。

今天的学习就到这里,你可以使用今天学习的技巧来改善一下你曾经的代码,如果想继续提高,欢迎关注我,每天学习进步一点点,就是领先的开始。如果觉得本文对你有帮助的话,欢迎点赞,评论,转发!!!

posted @ 2020-08-06 22:10  AlbertYang666  阅读(122)  评论(0编辑  收藏  举报

AlbertYang