文档地址: refactoringguru.cn/design-patt… 代码来源: www.cnblogs.com/TomXu/archi…
单例模式: 是一种创建型设计模式,
让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点
。
1. 保证一个类只有一个实例: 这样做最常见的原因是,控制某些共享资源(例如数据库或文件)的访问权限。
它的运作方式是这样的:如果你创建了一个对象,同时一会儿后你决定再创建一个新对象,此时你会获得之前已创建的对象,而不是一个新对象
。
2. 为该实例提供一个全局访问节点: 那些存储重要对象的全局变量吗?它们在使用上十分方便,但同时也非常不安全,因为任何代码都有可能覆盖掉那些变量的内容,从而引发程序崩溃。
和全局变量一样,单例模式也允许在程序的任何地方访问特定对象。但是它可以保护该实例不被其他代码覆盖。
还有一点:你不会希望解决同一个问题的代码分散在程序各处的。因此更好的方式是将其放在同一个类中,特别是当其他代码已经依赖这个类时更应该如此。
单例模式的实现
- 将默认构造函数设为私有,防止其他对象使用单例类的new运算符。
- 新建一个静态构建方法作为构造函数。该函数会“偷偷”调用私有构造函数创建一个对象,并将其保存在一个静态成员变量中。此后所有对于该函数的调用都将返回这一缓存对象。
// 数据库类会对`getInstance`(获取实例)方法进行定义以让客户端在程序各处// 都能访问相同的数据库连接实例。class Database is
// 保存单例实例的成员变量必须被声明为静态类型。
private static field instance: Database
// 单例的构造函数必须永远是私有类型,以防止使用`new`运算符直接调用构
// 造方法。
private constructor Database() is
// 部分初始化代码(例如到数据库服务器的实际连接)。
// ...
// 用于控制对单例实例的访问权限的静态方法。
public static method getInstance() is
// 核心代码
if (Database.instance == null) then
acquireThreadLock() and then
// 确保在该线程等待解锁时,其他线程没有初始化该实例。
if (Database.instance == null) then
Database.instance = new Database()
return Database.instance
// 最后,任何单例都必须定义一些可在其实例上执行的业务逻辑。
public method query(sql) is
// 比如应用的所有数据库查询请求都需要通过该方法进行。因此,你可以
// 在这里添加限流或缓冲逻辑。
// ...
伪代码调用
class Application is
method main() is
Database foo = Database.getInstance()
foo.query("SELECT ...")
// ...
Database bar = Database.getInstance()
bar.query("SELECT ...")
// 变量 `bar` 和 `foo` 中将包含同一个对象。
javascript实现
简单实现:
var mySingleton = function() {
/* 这里声明私有变量和方法 */
var privateVariable = 'something private';
function showPrivate() {
console.log(privateVariable);
}
/* 公有变量和方法(可以访问私有变量和方法) */
return {
publicMethod: function() {
showPrivate();
},
publicVar: 'the public can see this!'
};
};
var single = mySingleton();
single.publicMethod(); // 输出 'something private'
console.log(single.publicVar); // 输出 'the public can see this!'
如果我们想做到只有在使用的时候才初始化,为了节约资源的目的,我们可以另外一个构造函数里来初始化这些代码。
var Singleton = (function () {
var instantiated;
function init() {
/*这里定义单例代码*/
return {
publicMethod: function () {
console.log('hello world');
},
publicProperty: 'test'
};
}
return {
getInstance: function () {
if (!instantiated) {
instantiated = init();
}
return instantiated;
}
};
})();
/*调用公有的方法来获取实例:*/
// 这样只有 Singleton.getInstance() 时才进行初始化,进而调用实例上的方法
Singleton.getInstance().publicMethod();
单例一般是用在系统间各种模式的通信协调上,下面的代码是一个单例的最佳实践:
var SingletonTester = (function() {
//参数:传递给单例的一个参数集合
function Singleton(args) {
//设置args变量为接收的参数或者为空(如果没有提供的话)
var args = args || {};
//设置name参数
this.name = 'SingletonTester';
debugger
//设置pointX的值
this.pointX = args.pointX || 6; //从接收的参数里获取,或者设置为默认值
//设置pointY的值
this.pointY = args.pointY || 10;
}
//实例容器
var instance;
var _static = {
name: 'SingletonTester',
//获取实例的方法
//返回Singleton的实例
getInstance: function(args) {
if (instance === undefined) {
instance = new Singleton(args);
}
return instance;
}
};
return _static;
})();
var singletonTest = SingletonTester.getInstance({
pointX: 5
});
console.log(singletonTest.pointX); // 输出 5
单例模式适用性
- 如果程序中的某个类对于所有客户端只有一个可用的实例,可以使用单例模式。
- 如果你需要更加严格地控制全局变量,可以使用单例模式 例如:vuex。