javascript 设计模式之单体模式 面向对象学习基础

单体模式(singleton)

  单体是在脚本加载时创建的,能将一系列有关联的变量和方法组织为一个逻辑单元,逻辑单元里面的内容通过单一的变量进行访问;

  一个单体主要分为三部分

  用于访问内部信息的入口变量(如:Sky)

  属性(如:nickName/age/timeInfo)

  方法(如:sayHello)

  基本结构

  

复制代码 代码如下:

  var Sky = {

  /*

  * 作用一,变量管理

  */

  nickName: "sky",

  age: "26",

  /*

  * 作用二,加载中初始化变量

  * 在加载过程中执行并初始化Sky.info

  */

  timeInfo: function()

  {

  var _year = new Date().getFullYear();

  return _year;

  }(),

  /*

  * 作用三,函数管理,让你的函数看起来不再那么散乱

  */

  sayHello: function()

  {

  alert("hello,world!");

  }

  }

  //所有内部信息通过Sky这个变量进行访问;

  alert(Sky.timeInfo);

  以下是更详细的说明,看完了这篇文章,相信你应该差不多了解了,网上好多高手的js写法了,单体模式很常用。

  单体是一个用来划分命名空间并将一批相关的属性和方法组织在一起的对象,如果他可以被实例化,那么他只能被实例化一次。

  单体模式是javascript里面最基本但也是最有用的模式之一。

  特点:

  . 可以来划分命名空间,从而清除全局变量所带来的危险。

  . 利用分支技术来来封装浏览器之间的差异。

  . 可以把代码组织的更为一体,便于阅读和维护。

  单体的基本结构(正确写法):

  

复制代码 代码如下:

  /*Basic Singleton*/

  var Singleton = {

  attribute1:true,

  attribute2:10,

  method1:function(){},

     method2:function(){}

  };

  划分命名空间:

  

复制代码 代码如下:

  var box = {

  width:0,

  height:0,

  getArea:function(){

  return this.width*this.height;//js中对象成的访问必须是显示的,即this是不能省略的

  },

  init:function(w,h){

  // width = w;

  // height = h;这种方式相当于定义了两个全局变量,(没加var声明的变量为全局变量)

  // 并不是对对象width和height的赋值

  //下面是正确的

  this.width = w;

  this.height = h;

  }

  }//box划分了一个命名空间,命名空间里的变量只在空间里有效

  上面的单体中的所有的成员以及方法都是公有的(public),也就是在单体的外部可以对他们进行任意的改动,那为什么说单体提供了一个命名空间呢?

  我们继续:

  

复制代码 代码如下:

  var box = {

  width:0,

  height:0,//单体的变量

  getArea:function(){

  return width*height;//中的,width,height其实并不是单体的变量,而是在init中定义的全局变量

  }

  init:function(w,h){

  width = w;

  height = h;

  }

  }//init中width,height其实并不是单体的变量

  window.onload = function(){

  var init = box.getArea();

  alert(init);

  }

  由于没有对init中的width,height进行初始化,所以会报错,这样改一下:

  

复制代码 代码如下:

  var box = {

  width:0,

  height:0,

  getArea:function(){

  return width*height;

  },

  init:function(w,h){

  width = w;

  height = h;

  }

  }

  window.onload = function(){

  width = 0;

  height = 0;

  //or box.init(0,0);

  var init = box.getArea();

  alert(init);

  }

  发现可以了,由于init和 getArea所用的width和height并不是归单体所有的变量,而是一个全局变量,所以我们可以在单体外面进行随意调用而不受影响

  如果我们这样写一下就更明白了:

  

复制代码 代码如下:

  var box = {

  width:0,

  height:0,

  getArea:function(){

  return width*height;//js中对象成的访问必须是显示的,即this是不能省略的

  },

  init:function(w,h){

  width = w;

  height = h;

  }

  }//这里的width,height其实并不是单体的对象

  window.onload = function(){

  width = 0;

  height = 0;

  var width = box.getArea();

  alert(width);

  }

  这样写又会报错了,可见我们以上的方式对于全局变量并没有建立起一个命名空间,全局变量为我们带来了危险。所以最上面的写法是对的,我们来验证一下:

  

复制代码 代码如下:

  var box = {

  width:2,

  height:2,

  getArea:function(){

  return this.width*this.height;//js中对象成的访问必须是显示的,即this是不能省略的

  },

  init:function(w,h){

  this.width = w;

  this.height = h;

  }

  }

  window.onload = function(){

  width = 0;

  height = 0;

  var width = box.getArea();

  alert(width);

  }

  可见在window.onload中的width 和height已经没有干扰了,因为单体为单体中的width和height建立了一个命名空间。

  成员的属性:

  讨论完命名空间,我们来对单体变量和方法的属性做一下设定。学过其他语言的人(java,c++,c#...)都应该很了解其中类成员的public和private,

  虽然在javascript中没有这么严格的面向对象(oop),但是我们可以借助闭包来进行一个模仿,毕竟有的变量设为public是很不好的。

  

复制代码 代码如下:

  var circle = (function(){

  //pravite member!

  var r = 5;

  var pi = 3.1416;//后面用分号

  return{//public member

  getArea:function(){

  return r*r*pi;//访问私有成员不要加this

  },//后面用逗号

  //如果想改变r和pi的值,只能通过设置一个公有的函数来实现

  init:function(setR){

  r = setR;

  }

  }

  })()

  window.onload = function(){

  circle.r = 0;//无法访问私有成员,相当于又为circle创建了一个共有成员r

  alert(circle.getArea());

  circle.init(0);//通过公有的工具函数便可以访问了。

  alert(circle.getArea());

  };

  私有变量、方法是只读的,公有变量、方法是可读可写的

  访问:

  对于私有成员,直接访问即可,前面不用加任何修饰,

  对于公有的访问在单体作用域内前面要加上“this.”,在单体作用域外前面要加上“circle.”(单体名字.)

  呵呵,似乎有点味道了!

  .利用分支技术来来封装浏览器之间的差异

  注意的地方:

  a一定要用闭包,实现即时绑定

  b每个分支之间用分号隔开

  c最后返回的是分支的名字

  d调用的时候用单体名+分支的方法名;

  

复制代码 代码如下:

  // 利用单体的分支技术来定义XHR(XMLHttpRequest)对象,必须要用闭包才可以实现

  var XHR = (function(){

  //The three branches

  var standard = {

  cXHR:function(){

  return new XMLHttpRequest();

  }

  };

  var activeXNew = {

  cXHR:function(){

  return new ActiveXObject('Msxml2.XMLHttp');

  }

  };

  var activeXOld = {

  cXHR:function(){

  return new ActiveXObject('Microsoft.XMLHttp');

  }

  };

  //To assign(分配) the branch, try each method;return whatever doesn't fail

  var testObject;

  try{

  testObject = standard.cXHR();

  return standard;// return this branch if no error was thrown

  }catch(e){

  try{

  testObject = activeXNew.cXHR();

  return activeXNew;

  }catch(e){

  try{

  testObject = activeXOld.cXHR();

  return activeXOld;

  }catch(e){

  throw new Error('Create the XMLHttpRequestObject failed!');

  }

  }

  }

  })();

  window.onload = function(){

  alert(XHR.cXHR());

  }

  最后再啰嗦几句:

  对于单体据说是最常用的模式之一了,至于利弊嘛要在实践中慢慢的体会了,由于本人也是初学,所以没有太多的发言权,不足指出还忘高手指教