“这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战”
前言
在面试高级前端时,往往会遇到一些关于设计模式的问题,每次都回答不太理想。恰逢8月更文挑战的活动,准备用一个月时间好好理一下关于设计模式方面的知识点,给自己增加点面试的底气。
在往期几篇文章中详细介绍了设计模式的六大原则:
- 『面试的底气』—— 设计模式之单一职责原则|8月更文挑战
- 『面试的底气』—— 设计模式之开放封闭原则|8月更文挑战
- 『面试的底气』—— 设计模式之最少知识原则|8月更文挑战
- 『面试的底气』—— 设计模式之里氏代换原则|8月更文挑战
- 『面试的底气』—— 设计模式之依赖倒置原则|8月更文挑战
- 『面试的底气』—— 设计模式之接口隔离原则|8月更文挑战
接下来一起学习和实践设计模式之单例模式,在实践过程中要严格遵循六大原则,哪个原则不太熟悉,可以访问上面对应的链接。
定义
单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。
自己的理解
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止实例化多个对象。一个最好的办法就是,让类自身负责保持它的唯一实例,且这个类保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
实现单例模式
要实现一个简单的单例模式并不复杂,无非是用一个变量来缓存一个类实例化生成的对象,然后用这个变量来判断一个类是否已经实例化过。如何变量有值,则在下一次要获取该类的实例化生成的对象时,直接返回这个变量(之前实例化生成的对象)。
var Singleton = function(name) {
this.name = name;
this.instance = null;
};
Singleton.prototype.init = function() {
//...初始化
};
Singleton.getInstance = function(name) {
if (!this.instance) {
this.instance = new Singleton(name);
this.instance.init();
}
return this.instance;
};
var a = Singleton.getInstance('a');
var b = Singleton.getInstance('b');
console.log(a === b); // true
正常来说一个类每次实例化生成的对象是不同的,在上述代码中分别使用Singleton.getInstance
获取Singleton
类实例化生成的对象并赋值给对象a和对象b,执行console.log(a === b)
打印出true
,说明上述代码实现单例模式成功。
或不把实例化生成的对象挂载到类的属性上也可以实现,代码如下所示:
var Sington = function( name ){
this.name = name;
};
Singleton.prototype.init = function() {
//...初始化
};
Singleton.getInstance = (function(){
var instance = null;
return function( name ){
if ( !instance ){
instance = new Singleton( name );
instance.init();
}
return instance;
}
})();
变量instance
用来缓存类实例化生成的对象,用自执行匿名函数创建了一个闭包,把变量instance
存储在闭包中,每次执行Singleton.getInstance
时就可以用变量instance
来判断Singleton
类是否已经实例化过。
透明的单例模式
上述实现单例模式的方法中有一个问题,就是增加了这个类的“不透明性”,Singleton
类的使用者必须知道这是一个单例类,跟以往通过new XXX
的方式来实例化类,这里要使用Singleton.getInstance
来实例类。故要换一种方法来实现透明的单例模式。
const Singleton = (function() {
let instance;
const Singleton = function(name) {
if (instance) {
return instance;
}
this.name = name;
this.init();
return instance = this;
};
Singleton.prototype.init = function() {
//...初始化
};
return Singleton;
})();
const a = new Singleton('a');
const b = new Singleton('b');
console.log(a === b); // true
以上代码中,Singleton
类的构造函数是一个自执行的匿名函数,会构成一个闭包,可以把判断类是否实例化过的和缓存类实例化生成的对象的变量instance
缓存起来,最后在返回真正的Singleton
类构造方法。那么就可以使用new Singleton
来实例化Singleton
类。
必须遵循设计模式的原则
上述代码还不够完美,有两点:
-
把
Singleton
类的真正的构造函数放在自执行的匿名函数中返回,有点奇怪。 -
Singleton
类的构造函数中违背了设计模式的单一职责原则,做了二件事情,创建类实例化生成的对象和执行初始化init
方法,保证了只能实例化一次。
实现任何设计模式都要遵循设计模式的原则,要把“创建类实例化生成的对象和执行初始化init
方法”和“保证了只能实例化一次”这两个职责分隔开来。下面用代理实现单例模式。
const Singleton = function (name) {
this.name = name;
this.init();
}
Singleton.prototype.init = function () {
//...初始化
};
const PropxSingleton = (function () {
var instance;
return function (name) {
if (!instance) {
instance = new Singleton(name);
}
return instance;
}
})();
var a = new PropxSingleton('a');
var b = new PropxSingleton('b');
console.log(a === b);//true
以上用代理类propxSingleton
实现了Singleton
类的单例模式,而Singleton
类仍旧是一个普通的类,不影响在其它地方的使用。
然后以上代码还不够完美,假如要给另外一个类实现单例模式,得去修改代理类propxSingleton
的代码,不符合设计模式中的开放-封闭原则,得封装一个获取不同类的代理类propxSingleton
的getPropxSingleton
方法。
const Singleton = function (name) {
this.name = name;
this.init();
}
Singleton.prototype.init = function () {
//...初始化
};
const getPropxSingleton = function (customClass) {
return (function () {
var instance;
return function (name) {
if (!instance) {
instance = new customClass(name);
}
return instance;
}
})()
};
const PropxSingleton = getPropxSingleton(Singleton);
var a = new PropxSingleton('a');
var b = new PropxSingleton('b');
console.log(a === b); //true
用ES6来实现一个单例模式
以上都是用ES5实现的单例模式,现在都是使用ES6了,故用ES6来实现一个单例模式。
class Singleton {
constructor(name) {
this.name = name;
this.init();
}
init() {
//...初始化
}
}
const getPropxSingleton = function (customClass) {
let instance = null;
return class {
constructor() {
if (instance) return instance;
return instance = new customClass(...arguments)
}
}
};
const PropxSingleton = getPropxSingleton(Singleton);
var a = new PropxSingleton('a');
var b = new PropxSingleton('b');
console.log(a === b); //true
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!