博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《javascript设计模式》笔记之第五章:单体模式
阅读量:4598 次
发布时间:2019-06-09

本文共 6279 字,大约阅读时间需要 20 分钟。

一:单体的基本结构

最简单的单体,实际就是一个对象字面量:
var Singleton = {  attribute1: true,  attribute2: 10,  method1: function() {  },  method2: function(arg) {  }};
二:划分命名空间
单体一个很重要的功能就是划分命名空间,这节其实没什么好说的。。
然后,最好的做法是将命名空间再进一步统一,使自己的所有代码都通过一个全局对象来访问,例子:
var GiantCorp = {};GiantCorp.Common = {  // A singleton with common methods used by all objects and modules.};GiantCorp.ErrorCodes = {  // An object literal used to store data.};GiantCorp.PageHandler = {  // A singleton with page specific methods and attributes.};
然后这样的话,与外部的代码发生冲突的可能性就超级少了
三:用作特定网页专用代码的包装器的单体
单体的另一个重要的功能就是包装网页专用代码:
Namespace.PageName = {  // Page constants.  CONSTANT_1: true,  CONSTANT_2: 10,  // Page methods.  method1: function() {  },  method2: function() {  },  // Initialization method.  init: function() {  }}
然后就调用这些代码
addLoadEvent(Namespace.PageName.init);
接下来举一个实际使用的例子:我们现在写网页基本上必写的就是用ajax提交表单,那么我们怎样用单体来包装这些代码呢?下面就是一个演示:
先来反例(我自己之前的做法~~~):
var formID = document.getElementById("form");formID.addEventListener('submit',formSubmit,false);function formSubmit(e) {        //阻止表单默认动作,然后用ajax发送数据        //接受数据之后调用callBack函数}function callBack(data) {        //用ajax提交表单之后的回调函数
这样的话污染了超级多的全局变量~~~
然后学习这章之后的做法~~~
var GiantCorp = window.GiantCorp || {};GiantCorp.RegPage = {        formID: 'form',        callBack: function(data) {                //用ajax提交表单之后的回调函数        },        formSubmit: function(e) {                //阻止表单默认动作,然后用ajax发送数据                //接受数据之后调用callBack函数        },        init: function(e) {                GiantCorp.RegPage.formEl = document.getElementById(GiantCorp.RegPage.formID);                GiantCorp.RegPage.formEl.addEventListener('submit',GiantCorp.RegPage.formSubmit,false);        }}GiantCorp.RegPage.init();
注意第一行代码,意思就是如果之前定义过GiantCorp的话就不管,不然就赋予一个空对象给GiantCorp,这样的代码在很多地方都会看到。
四:拥有私用成员的单体
拥有私用成员的最简单方法就是在属性前加下划线_来区分:
GiantCorp.DataParser = {  // Private methods.  _stripWhitespace: function(str) {    return str.replace(/\s+/, '');  },  _stringSplit: function(str, delimiter) {    return str.split(delimiter);  },    // Public method.  stringToArray: function(str, delimiter, stripWS) {    if(stripWS) {      str = this._stripWhitespace(str);    }    var outputArray = this._stringSplit(str, delimiter);    return outputArray;  }};
上面的代码不用去理解它,看到下划线_就把它当成是私有属性就可以了
此外stringToArray的函数里面用了this来直接调用单体里面的其他方法,不过使用起来注意它有时候指向的对象的问题!
接下来是使用闭包来实现真正拥有私用成员的单体:
MyNamespace.Singleton = (function() {  // Private members.  var privateAttribute1 = false;  var privateAttribute2 = [1, 2, 3];    function privateMethod1() {    ...  }  function privateMethod2(args) {    ...  }  return { // Public members.    publicAttribute1: true,    publicAttribute2: 10,        publicMethod1: function() {      ...    },    publicMethod2: function(args) {      ...    }  };})();
注意是公共成员都是放在return里面的,其他都是私有的。
这种模式是JavaScript中最流行,应用最广泛的模式之一
五:惰性实例化
又来一个比较高级的做法,那就是惰性实例化:当我们需要用到这段代码的时候才创建它。换种方法说就是这样调用其方法:Singleton.getInstance().methodName(),而不是这样调用:Singleton.methodName()。其中getInstance方法会检查该单体是否已经被实例化。如果还没有,那么它将创建并返回其实例,如果单体已经实例过,那么它将返回现有实例。
 
实现步骤一(单体的所有代码移动一个名为constructor的方法中):
MyNamespace.Singleton = (function() {  function constructor() { // All of the normal singleton code goes here.    // Private members.    var privateAttribute1 = false;    var privateAttribute2 = [1, 2, 3];      function privateMethod1() {      ...    }    function privateMethod2(args) {      ...    }    return { // Public members.      publicAttribute1: true,      publicAttribute2: 10,          publicMethod1: function() {        ...      },      publicMethod2: function(args) {        ...      }    }  }  })();
上面注意constructor是包含单体里面所有代码的。
实现步骤二(创建一个单体控制的函数,并返回到单体):
MyNamespace.Singleton = (function() {    function constructor() { // All of the normal singleton code goes here.    ...  }    return {    getInstance: function() {      // Control code goes here.    }  }})();
实现步骤三(创建个私有变量用于判断是否已经实例化,并且在getInstance实现判断逻辑):
MyNamespace.Singleton = (function() {    var uniqueInstance; // Private attribute that holds the single instance.    function constructor() { // All of the normal singleton code goes here.    ...  }    return {    getInstance: function() {      if(!uniqueInstance) { // Instantiate only if the instance doesn't exist.        uniqueInstance = constructor();      }      return uniqueInstance;    }  }})();
此外,可以用 var MNS = MyNamespace.Singleton的方法简化命名空间,但是要注意this指向问题!
六:分支
利用分支可以实现判断浏览器支持哪一种代码,然后对该浏览器使用专用的代码:
MyNamespace.Singleton = (function() {  var objectA = {    method1: function() {      ...    },    method2: function() {      ...    }  };  var objectB = {    method1: function() {      ...    },    method2: function() {      ...    }  };  return (someCondition) ? objectA : objectB;})();
用上面这样的分支我们就可以用来实现如果是IE8就返回第一种单体,如果不是就返回第二种单体了。
七:示例:用分支技术创建XHR对象
如果要兼容老旧的浏览器使用ajax,那就可以用这种技术了
例子:
/* SimpleXhrFactory singleton, step 1. */var SimpleXhrFactory = (function() {    // The three branches.  var standard = {    createXhrObject: function() {      return new XMLHttpRequest();    }  };  var activeXNew = {    createXhrObject: function() {      return new ActiveXObject('Msxml2.XMLHTTP');    }  };  var activeXOld = {    createXhrObject: function() {      return new ActiveXObject('Microsoft.XMLHTTP');    }  };  })();/* SimpleXhrFactory singleton, step 2. */var SimpleXhrFactory = (function() {    // The three branches.  var standard = {    createXhrObject: function() {      return new XMLHttpRequest();    }  };  var activeXNew = {    createXhrObject: function() {      return new ActiveXObject('Msxml2.XMLHTTP');    }  };  var activeXOld = {    createXhrObject: function() {      return new ActiveXObject('Microsoft.XMLHTTP');    }  };    // To assign the branch, try each method; return whatever doesn't fail.  var testObject;  try {    testObject = standard.createXhrObject();    return standard; // Return this if no error was thrown.  }  catch(e) {    try {      testObject = activeXNew.createXhrObject();      return activeXNew; // Return this if no error was thrown.    }    catch(e) {      try {        testObject = activeXOld.createXhrObject();        return activeXOld; // Return this if no error was thrown.      }      catch(e) {        throw new Error('No XHR object found in this environment.');      }    }  }})();

转载于:https://www.cnblogs.com/oadaM92/p/4356906.html

你可能感兴趣的文章
避免js拼接页面的小技巧
查看>>
面试题(Spring)
查看>>
VS恢复默认设置
查看>>
BZOJ.3591.最长上升子序列(状压DP)
查看>>
JS - 局部方法改变全局变量的值
查看>>
Vue引入远程JS文件
查看>>
4067: [Ctsc2015]gender 动态规划 网络流
查看>>
Spring的Bean内部方法调用无法使用AOP切面(CacheAble注解失效)
查看>>
分布式事务之深入理解什么是2PC、3PC及TCC协议?
查看>>
Vim插件:Unite新手指导(译)
查看>>
pymysql实现MySQL与Python交互
查看>>
迭代器与生成器
查看>>
从DataTable到List<Model>(C#.net)
查看>>
JavaScript 垃圾回收机制分析
查看>>
CM+CDH安装教程(CentOS)
查看>>
C/C++中extern和static
查看>>
第一阶段linux结束
查看>>
网络流+二分图模板
查看>>
[MQ]关于ActiveMQ的配置
查看>>
tomcat部署Jenkins并配置jdk、maven、git
查看>>