javascript设计模式--单例模式(Singleton)
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
/* 单体 */ /**
* 单例模式
*
* 定义:
* 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
*
* 本质:
* 控制实例数目
*
* 单例模式是用来保证这个类在运行期间只会被创建一个类实例,另外,单例模式还提供了一个全局唯一访问这个类实例的访问点,就是getInstance方法。不管采用懒汉式还是俄汉式的实现方式,这个全局访问点是一样的。
*/ // 懒汉式
// 在使用对象实例的时候才会创建
var Singleton = (function(){
// 顶一个以变量来存储创建好的类实例
var uniqueInstance = null;
// 单例可以有自己的属性
var singletonData = ''; var Singleton = function(){
//...
}; return {
// 定义一个方法来为客户端提供类实例
getInstance: function(){
if(uniqueInstance === null) {
uniqueInstance = new Singleton();
} return uniqueInstance;
},
// 单例可以有自己的操作
singletonOperation: function(){
// 功能处理
},
// 让外部通过这些方法来访问属性的值
getSingletonData: function(){
return singletonData;
}
};
}()); // 俄汉式
// 在装载类的时候就创建对象实例。
var Singleton = (function(){
var uniqueInstance = new Singleton();
var singletonData = ''; function Singleton(){} return {
getInstance: function(){
return uniqueInstance;
},
singletonOperationL function(){},
// 让外部通过这些方法来访问属性的值
getSingletonData: function(){
return singletonData;
}
};
}()); /*------------------
划分命名空间
------------------------*/
var MyNameSpace = {
findProduct: function (id) {
//...
},
others: function () { }
//Othermethods can go here as well
}; // Later in your page, another programmer adds
var resetProduct = $('reset-product-button');
var findProduct = $('find-product-button'); // nothing was overwriitten // 包装特定网页专用代码的单体骨架
/* Generic Page Object */
var Namespace = Namespace || {};
Namespace.PageName = { // Page constants
CONSTANT_1: true,
CONSTANT_2: 10, // Page methods
method1: function () {
},
method2: function () {
}, // Initialization method
init: function () { }
}; // Invoke the initialization method after the page loads
ADS.addLoadEvent(Namespace.PageName.init); // 下面的单体会查找并劫持(hijiack)一个特定的表单
/* RegPage singleton,page handler object */
var GiantCorp = GiantCorp || {};
GiantCorp.RegPage = {
// Constants
FORM_ID: 'reg-form',
OUTPUT_ID: 'reg-results', // form handling methods
handleSubmit: function (e) {
e.preventDefault(); // stop the normal form submission var data = {};
var inputs = GiantCorp.RegPage.formEl.getElementsByTagName('input'); // collext the values of the input fields in the form
for (var i = 0, len = inputs.length; i < len; i++) {
data[inputs[i].name] = inputs[i].value;
} // send the form values back to the server
GiantCorp.RegPage.sendRegistration(data);
},
sendRegistration: function (data) {
// make an XHR request and call displayResult() when
// the response was received
// ...
},
displayResult: function (response) {
// output the response directly into the output element,
// we are assuming the server will send back formatted HTML
GiantCorp.RegPage.outputEl.innerHTML = response;
},
// initialization method
init: function () {
// get the form and output elements
GiantCorp.RegPage.formEl = $(GiantCorp.RegPage.FORM_ID);
GiantCorp.RegPage.outputEl = $(GiantCorp.RegPage.OUTPUT_ID); // Hijack the form submission
ADS.addEvent(GiantCorp.RegPage.formEl, 'submit', GiantCorp.RegPage.handleSubmit);
}
}; // invoke the initialization method after the page loads
ADS.addLoadEvent(GiantCorp.RegPage.init); /*---------------------
拥有私用成员
-----------------------*/
// 使用下划线表示法
/* DataParser singleton,converts charcter delimited strings into array */
GiantCorp.DataParser = {
// private methods
_stripeWhitespace: 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._stripeWhitespace(str);
}
var outputArray = this._stringSplit(str, delimiter);
return outputArray;
}
}; // 使用闭包
/*
与构造函数中创建正真的私用成员的做法相似。先前的做法是把变量和函数定义在构造函数体内(不使用this关键字)以使其成为私用成员,此外还在构造函数体内定义了所有的特权方法并用this关键字使其可被外界访问。每生成一个该类的实例时,所有声明在构造函数内的方法和属性都会再次创建一份。这可能会非常低效。
因为单体只会被实例化一次,所以不用担心自己在构造函数中声明了多少成员。
*/
/* Singleton as an Object Literal */
MyNamespace.Singleton = {}; /* Singleton with Private Members,step 1. */
MyNamespace.Singleton = function () {
return {};
}();
// 上面两个例子中所创建的两个MyNamespace.Singleton完全相同 // 在匿名函数定义之外再嵌套上一对圆括号,这在所创建的单体较为庞大时尤其有用
MyNamespace.Singleton = (function () {
return {};
})(); /* Singleton with Private Members,step 2. */
MyNameSpace.Singleton = (function () {
return {
// public members
publicAttribute1: true,
publicAttribute2: 10,
publicMethod1: function () {
//...
},
publicMethod2: function (args) {
//...
}
};
})(); // 添加私用成员
/* Singleton with Private Member,step 3. */
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) {
//...
}
};
})(); /*
这种单体模式又称模块模式,指的是它可以把一批相关方法和属性组织为模块并起到划分命名空间的作用
*/
/* now using true private methods */
GiantCorp.DataParser = (function () {
// private attributes
var whitespaceRegex = /\s+/; // private methods
function stripWhiteSpace(str) {
return str.replace(whitespaceRegex, '');
} function stringSplit(str, delimiter) {
return str.split(delimiter);
} // everything returned in the object literal is public,but can access
// the members in the closure create above
return {
// public method
stringToArray: function (str, delimiter, stripWS) {
if (stripWS) {
str = stripWhiteSpace(str);
}
var outputArray = stringSplit(str, delimiter);
return outputArray;
}
};
})(); /*----------------
惰性实例化
-------------------*/
/*
单体对象都是在脚本加载时被创建出来。对于资源密集型的或配置开销甚大的单体,也许更合理的做法是将其实例化推迟到需要使用它的时候。这种技术被称为惰性加载(lazy loading),它最常用于那些必须加载大量数据的单体。
而那些被用作命名空间,特定网页专用代码包装器或组织相关实用方法的工具的单体最好还是立即实例化。
这种惰性加载单体的特别之处在于,对他们的访问必须借助于一个静态方法。应该这样调用其方法:Singleton.getInstance().methodName(),getInstace()方法会检查该单体是否已经被实例化。如果还没有,那么它将创建并返回其实例;如果单体已经实例化,那么它将返回现有实例
*/
// 第一步是把单体的所有代码移到一个名为constructor的方法中
/* general skeleton for a lazy loading singleton, */
MyNameSpace.Singleton = (function () {
var uniqueInstance; // private attribute that holds the single instance
function constructor() {
// all od 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) {
//...
}
};
} return {
getInstance: function () {
// control code goes here
if (!uniqueInstance) {
// instantiate only if the instance doesn't exist
// 如果没有被实例化,则把constructor()的结果赋给uniqueInstance
uniqueInstance = constructor();
}
// 被实例化后直接返回uniqueInstance,不需要每次都执行函数
return uniqueInstance;
}
};
})(); // usage
var MNS = MyNameSpace.Singleton;
MNS.getInstance().publicMethod1();
/*
这样做会创建一个全局变量,所以最好还是把它声明在一个特定网页专用代码包装器单体中。在存在单体嵌套的情况下,会出现一些作用域方面的问题。在这种场合下访问其他成员最好是用完全限定名(比如:GiantCorp.SingletonName)而不是this。
*/ /*----------------
分支 branching
------------------*/
/*
分支是一种用来把浏览器间的差异封装到在运行期间进行设置的动态方法中的技术。
举个例子,假设我们需要创建一个返回XHR对象的方法。这种XHR对象在大多数浏览器中是XMLHttpRequest类的实例,而在IE早起版本中则是某种ActiveX类的实例。这样一个方法通常会进行某种浏览器嗅探或对象探测。如果不用分支技术,那么每次调用这个方法时,所有那些浏览器嗅探代码都要再次运行,会缺乏效率。
*/
// 可以创建两个不同的对象字面量,并根据某种条件将其中之一赋给那个变量
MyNameSpace.Singleton = (function () {
var objectA = {
method1: function () {
//...
},
method2: function () {
//...
}
};
var objectB = {
method1: function () {
//...
},
method2: function () {
//...
}
}; return (someCondition) ? objectA : objectB;
})(); // 用分支技术创建XHR对象
/* 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');
}
}; // To assign the branch, try each method,return whatever doesn't fail
var testObject;
try {
testObject = standard.createXhrObject();
return standard;
} catch (e) {
try {
testObject = activeXNew.createXhrObject();
return activeXNew;
} catch (e) {
try {
testObject = activeXOld.createXhrObject();
return activeXOld;
} catch (e) {
throw new Error('No XHR object found in this environment');
}
}
}
})(); /*
单体模式之利
单体模式的主要好处在于它对代码的组织作用。把相关方法和属性组织在一个不会被多次实例化的单体中。可以使代码的调试和维护变得更轻松。描述性的命名空间还可以增强代码的自我说明性,有利于新手阅读和理解。把你的方法包裹在单体中,可以防止他们被其它程序员误改,还可以防止全局命名空间被一大堆变量弄得一团糟。
单体模式的一些高级变体可以在开发周期的后期用于对脚本进行优化,提升其性能。使用惰性实例化技术,可以直到需要一个对象的时候才创建它,从而减少那些不需要它的用户承受的不必要的内存消耗(还可能包带宽消耗)。分支技术则可以用來创建高效的方法,不用管浏览器或环境的兼容性如何。通过根据运行时的条件确定赋给单体变量的对象字面量,你可以创建出为特定环境量身定制的方法,这种方法不会再每次调用时都一再浪费时间去检查运行环境。
*/ /*
单体模式之弊
由于单体模式提供的是一种单体访问,所以它有可能导致模块间的强耦合。有时创建一个可实例化的类更为可取,哪怕它只会被实例化一次。因为这种模式可能会导致类间的强耦合,所以它不利于单元测试。你无法单独测试一个调用了来自单体的方法的类,而只能把它与那个单体作为一个单元一起测试。单体最好还是留给定义命名空间和实现分支型方法这些用途。在这些情况下,耦合不是什么问题。
*/
</script>
</body>
</html>
javascript设计模式--单例模式(Singleton)的更多相关文章
- 设计模式 单例模式(Singleton) [ 转载2 ]
设计模式 单例模式(Singleton) [ 转载2 ] @author java_my_life 单例模式的结构 单例模式的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类 ...
- 设计模式 单例模式(Singleton) [ 转载 ]
设计模式 单例模式(Singleton) [ 转载 ] 转载请注明出处:http://cantellow.iteye.com/blog/838473 前言 懒汉:调用时才创建对象 饿汉:类初始化时就创 ...
- JAVA设计模式-单例模式(Singleton)线程安全与效率
一,前言 单例模式详细大家都已经非常熟悉了,在文章单例模式的八种写法比较中,对单例模式的概念以及使用场景都做了很不错的说明.请在阅读本文之前,阅读一下这篇文章,因为本文就是按照这篇文章中的八种单例模式 ...
- JavaScript设计模式-单例模式、模块模式(转载 学习中。。。。)
(转载地址:http://technicolor.iteye.com/blog/1409656) 之前在<JavaScript小特性-面向对象>里面介绍过JavaScript面向对象的特性 ...
- 浅谈设计模式--单例模式(Singleton Pattern)
题外话:好久没写blog,做知识归纳整理了.本来设计模式就是个坑,各种文章也写烂了.不过,不是自己写的东西,缺少点知识的存在感.目前还没做到光看即能记住,得写.所以准备跳入设计模式这个大坑. 开篇先贡 ...
- 探索Javascript设计模式---单例模式
最近打算系统的学习javascript设计模式,以便自己在开发中遇到问题可以按照设计模式提供的思路进行封装,这样可以提高开发效率并且可以预先规避很多未知的问题. 先从最基本的单例模式开始. 什么是单例 ...
- [工作中的设计模式]单例模式singleton
一.模式解析: 单例模式是最简单和最常用的设计模式,面试的时候,不管新毕业的学生还是已经工作多年的筒子,对单例模式基本都能聊上两句.单例模式主要体现在如下方面: 1.类的构造函数私有化,保证外部不能直 ...
- JavaScript设计模式 - 单例模式
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 一.实现一个标准的单例模式,用一个变量来标志当前是否已经为某个类创建过对象, 如果是,则在下一次获取该对象实例时,直接返回之前创建的对 ...
- javascript设计模式——单例模式
前面的话 单例模式是指保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式是一种常用的模式,有一些对象往往只需要一个,比如线程池.全局缓存.浏览器中的window对象等.在javaScri ...
随机推荐
- python datetime date time详解
之前一直被datetime,date,time弄的有点乱,可能是因为看文档每太看明白,找到了两篇文章供大家阅读都是转载的,其中有些名词这里解释一下: 世界协调时间(Universal Time Coo ...
- PHPStorm配置支持友好的Laravel代码自动提示
在项目的composer.json "barryvdh/laravel-ide-helper":"dev-master" 项目config/app.php Ba ...
- Effective C# 学习笔记(原则二:为你的常量选择readonly而不是const)
原则二.为你的常量选择readonly而不是const Prefer readonly to const 对于常量,C#里面有两个不同的版本:运行时常量(readonly)和编译时常量(co ...
- 多路转接之poll和select
先看poll(): #include <stdio.h> #include <stdlib.h> #include <string.h> #include < ...
- linux kernel 0.11 bootsect
bootsect作用 ①将自己移动到0x90000处 ②将setup从磁盘读到0x90200处 ③将system从磁盘读到0x10000处 寄存器 汇编代码中存在:数据段data seg 栈段 sta ...
- EChart 关于图标控件的简单实用
1.下载前段框架并放入项目中去. 2.在js中调用 <!DOCTYPE html> <html lang="en"> <head> <me ...
- Redis 客户端配置及示例
一.redis自定义配置节点 <configSections> <section name ="RedisConfig" type="Amy.Toolk ...
- exception -----> Functions
/* current_exception */ exception_ptr current_exception() noexcept; 返回指向当前异常(或其副本)的智能指针[具体返回对象本身还是副本 ...
- 混合使用C和C++
C++作为C语言的扩展集,几乎所有的C程序都可以在C++中编译和运行,但是要注意C程序中可能使用了C++中的关键字作为变量,比如在C中:int class = 0; 但这在C++中不行.出于方便性,我 ...
- Android开发随笔之ScrollView嵌套GridView[ 转]
今天在开发中用到了需要ScrollView嵌套GridView的情况,由于这两款控件都自带滚动条,当他们碰到一起的时候便会出问题,即GridView会显示不全,为了解决这个问题查了N多资料,某个谷歌的 ...