1、单例模式
为什么要使用单例模式?
在某些情况下,在处理多个模块的数据时,他们没有什么联系,但是我们想要用一个公共的部分来进行储存状态或者数据。
为了保证这些模块之间能够稳定统一,那就要求这个公共部分是唯一的,各个模块之间所获取的数据与状态才能够保持一致
这时候我们使用到了单例模式,顾名思义,就是单个实例。
单例模式的特点
单例模式一般用在es6类中
单例在全局的每个位置都可以调用到
单例自始至终都是初始创建的实例,无法被修改、覆盖
ts单例模式设计
export default class Modle extends EventTarget{ //单例继承事件对象类,具备抛发事件功能
private static _instance?:Modle; //声明私有静态属性,存储单例
private _num!:number; //设置状态存储变量,这个私有变量无法直接获取与设置
constructor(){
super();
}
static get getInstance() { //通过get方法来获取这个单例,如果没有创建实例对象,有则直接返回这个实例对象
if (!Modle._instance) Modle._instance=new Modle();
return Modle._instance;
}
public set num (value:number) { //set方法拦截处理状态
this._num=value;
this.dispatchE(value);
}
private dispatchE(value:number) { //通过事件抛发将状态改变通知所有注册这个单例change事件的对象
let evt:fsEvent=new Event("change");
evt.num=value;
Modle.getInstance.dispatchEvent(evt);
}
public get num () { //get方法返回状态信息
return this._num;
}
}
在全局模块中使用该单例
import Modle from "./js/instance/Modle.js";
Modle.getInstance.num=12;
需要注意的是类中的_instance是私有属性但是他只有在ts文件直接使用Modle._instance() 会进行报错,但是在js引入时会正常访问该属性,所以在使用js文件时要格外注意
Es6单例模式设计
与ts相比js在设计时主要在于需要添加属性保护使js的单例不能被修改
export default class Modle{
static _instance;
constructor () {}
static getInstance() {
if (!Modle._instance) Modle._instance=new Modle();
return Modle._instance;
}
}
这种方法虽然通过getInstance获取到的是同一个实例,但是_instance被暴露在外,这种方式不安全
所以要考虑别的方法将_instance保护起来
方法1 freez 冻结
在创建单例后,通过freez冻结整个类,这样类的属性无法更改从而起到了保护的作用
export default class Modle{
constructor () {};
static getInstance() {
if (!Modle._instance) {
Modle._instance=new Modle();
Object.freeze(Modle); //创建单例后立即冻结整个类
}
return Modle._instance;
}
}
Modle.getInstance();//立即执行一次实现冻结,防止外部修改
冻结以后我们可以往使用和更改单例的方法属性,但无法直接替换整个单例对象
import Modle from './js/Modle.js';
Modle.getInstance().data=30;
console.log(Modle.getInstance().data);
方法2 defineProperty设置属性
export default class Modle{
constructor () {};
static getInstance() {
if (!Modle._instance) {
Object.defineProperty(Modle,"_instance",{
value:new Modle()
});
}
return Modle._instance;
}
}
Modle.getInstance();
这个与冻结的原理相似,设置属性不可枚举、不可修改、不可删除
方法3 get方法设置只读
export default class Modle{
constructor () {};
static get instance() { //只设置get方法instance属性为只读属性,他用于外部调用时返回指定值,他返回的是单例
if (!Modle._instance) {
Object.defineProperty(Modle,"_instance",{ //_instance为单例
value:new Modle()
});
}
return Modle._instance;
}
}
Modle.instance;
总结:
方法1 保护了getInstance方法、_instance实例,保证单例,但是这个类却不能再增、删、改其中的属性
方法2 保护了_instance实例,该类也可以进行其他属性的更改,但是却没有保护getInstance方法,如果修改了这个获取方法,会导致单例无法通过方法获取
方法3 结合了1、2的优点,通过get限制获取方法为只读,不能修改,在内部通过defineProperty来设置单例为不可枚举、不可删除、不可修改属性,这样在不影响类其他属性的情况下,实现了单例。