08.Javascript设计模式之门面模式----Facade
门面模式描述的是对象的结构模式。外部与一个子系统的通信必须通过一个系统的一个门面对象进行,这就是门面模式。门面模式也被称为外观模式、正面模式。这个模式在系统中经常被用到,也是一个比较简单的模式。
角色划分
门面模式具备如下两个角色:
1. 门面角色
客户端可以调用这个角色方法,此角色知晓相关的(一个或多个)子系统的功能和责任。本角色会将所有从客户端发来的请求委派到相应的子系统去。
2. 子系统角色
可以同时有一个或多个子系统。每一个子系统都不是一个单独的类,而是一些类的集合。每一个子系统都可以被客户端直接调用,或被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另一个客户端而已。
下面仍然是通过例子的形式来说明这个传说中的门面模式。
门面模式----示例1
门面模式其实是一个非常简单的设计模式,用通俗的语言来讲,就是:你是一个公司的老板,我是你的客户,现在我想要你们公司给我开发一个软件,而开发 软件这个工作是由你的员工去完成的,我由不能直接找你的员工来完成这件事,必须先告诉你,由你去发号司令,安排员工完成,最后给我反馈。这个过程中,我是 一个外界角色,你的员工是子系统,你就是一个门面。
现在我们就这个命题展开设计:
//这里定义一个员工接口,假定每个员工在一个软件开发的过程中都需要经历四个阶段:设计、编码、测试、提交 var IStaff = new Interface("IStaff",["design","coding","test","submit"]); //这里定义了一个老板接口,假定每个老板需要做四件事:安排任务、任务监督、验收产品、售出 var IBoss = new Interface("IBoss",["assign","manage","checkProduct","sellProduct"]); //创建员工类 var Staff = function(){}; implements(Staff,IStaff); //实现几个抽象方法 Staff.prototype.design = function(){ alert("设计完成"); }; Staff.prototype.coding = function(){ alert("编码完成"); }; Staff.prototype.test = function(){ alert("测试完成"); }; Staff.prototype.submit = function(){ alert("提交完成"); }; //创建老板类 var Boss = function(){}; implements(Boss,IBoss); //实现几个抽象方法 Boss.prototype.assign = function(){ alert("任务安排完成"); }; Boss.prototype.manage = function(){ for(var i = 0;i < 10;i++){ //假设这个产品需要10个人共同来完成 var staff = new Staff(); staff.design(); staff.coding(); staff.test(); staff.submit(); } alert("产品开发完成"); }; Boss.prototype.checkProduct = function(){ alert("产品验收通过"); }; Boss.prototype.sellProduct = function(){ alert("产品已卖出"); };
到这里,我们的门面设计其实已经结束了,最后一步,就是要体现出门面模式的用法了:
var boss = new Boss(); //我需要产品,并通知老板你 boss.assign(); //你安排任务 boss.manage(); //监工 boss.checkProduct(); //产品验收 boss.sellProduct(); //产品售出
就这样的一个简单设计,就完成了门面模式的例子,非常的简单。
门面模式----示例2
还有一个非常经典的门面模式的例子,就是很多Javascript库中所实装的Event类,基本结构为:
JsLib.event.Event = { getEvent: function(e) { }, getTarget: function(e) { }, stopPropagation: function(e) { }, preventDefault: function(e) { }, stopEvent: function(e) { } };
分析上面的代码,其实有用的方法是stopPropagation和preventDefault,然而它们所需要的参数必须解决各种浏览器的兼容 问题,其次,这两个方法名太长也不容易记住,因此有了stopEvent方法,我们决定在这个方法的内部来解决浏览器的兼容问题,并且封装两个难于记住的 方法:
JsLib.event.Event = { getEvent: function(e) { return window.event || e; }, getTarget: function(e) { return e.srcElement || e.target; }, stopPropagation: function(e) { if (e.stopPropagation) { //not IE e.stopPropagation(); } else { //IE e.cancelBubble = true; } }, preventDefault: function(e) { if (e.preventDefault) { //not IE e.preventDefault(); } else { //IE e.returnValue = false; } }, stopEvent: function(e) { var evt = this.getEvent(e); //格式化event对象,处理浏览器兼容第一步 this.stopPropagation(e); //阻止冒泡 this.preventDefault(e); //阻止默认行为 } };
OK,设计到这里,作Javascript程序员来说,处理冒泡和默认行为就变得非常简单了,比如,不让表单提交,我们可以这样来添加监听器:
addEvent(formElement,"submit",function(e){ //只需要调用一个方法,就能实现 JsLib.event.Event.stopEvent(e); alert("偶也,你点击了提交按钮吧?可是表单没有提交哦!"); });
好了,有关门面模式,就介绍到这里。
其中必定有描述不当的地方,还请原谅。Thanks