单例模式在JavaScript与TypeScript中的几种设计方式

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来设置单例为不可枚举、不可删除、不可修改属性,这样在不影响类其他属性的情况下,实现了单例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值