如何创建一个无法在 TypeScript 外部实例化的类?



在Java中,我们有私有构造函数

public class Singleton{
    private static volatile Singleton INSTANCE = null;
    private Singleton(){ }
    public static Singleton getInstance(){
        if(INSTANCE == null){
            synchronized(Singleton.class){
                if(INSTANCE == null){
                    INSTANCE = new Singleton();
                }
            }
        }
    return INSTANCE;
    }
}

这使得类不能在类之外进行初始化。TypeScript 中有类似的东西吗?

我将从java部分开始,并将在@DavideLorenzoMARINO写的内容上添加一件额外的东西,那就是volatile关键字:

class MySingleton {
    private static volatile MySingleton instance;
    private MySingleton() {
        // do what ever
    }
    public static MySingleton getInstance() {
        if (MySingleton.instance == null) {
            MySingleton.instance = new MySingleton();
        }
        return MySingleton.instance;
    }
}

如果您真的想确保这在多线程环境中有效,那么您甚至可能需要考虑"双重检查锁定"方法:

class MySingleton {
    private static volatile MySingleton instance;
    private MySingleton() {
        // do what ever
    }
    public static MySingleton getInstance() {
        if (MySingleton.instance == null) {
            synchronized (MySingleton.class) {
                if (MySingleton.instance == null) {
                    MySingleton.instance = new MySingleton();
                }
            }
        }
        return MySingleton.instance;
    }
}
至于打字稿

部分,我认为这种模式在打字稿中效果不佳,因为与运行时的 java 不同,没有什么可以阻止另一个开发人员实例化多个实例。

如果您信任使用代码的开发人员,那很好,但如果不是,那么为什么不将实例括在模块/命名空间中以便隐藏实现呢?

像这样:

namespace MySingleton {
    class MySingletonInstance {
        echo(value: string): string {
            console.log(value);
            return value;
        }
    }
    export var instance = new MySingletonInstance();
}

但是由于你只会有一个类的实例,那么我认为在javascript中根本不使用类更有意义,它只会让事情变得更加冗长,你可以简单地:

namespace MySingleton {
    export interface MySingletonInstance {
        echo(value: string): string;
    }
    export var instance: MySingletonInstance = {
        echo: value => {
            console.log(value);
            return value;
        }
    }
}

这样的事情应该有效:

class Singleton {
    private static _instance:Singleton = new Singleton();
    constructor() {
        if (Singleton._instance){
            throw new Error("Error: use getInstance()");
        }
        Singleton._instance = this;
    }
    public static getInstance():Singleton {
        return Singleton._instance;
    }
    ...
 }

同样在 java 中不需要使用延迟初始化,因为如果不使用单例,则不会初始化。更好的方法:

public class Singleton {
    private static Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public Singleton getInstance(){
        return INSTANCE;
    }
}

为了回答 Zhipeng 的评论,静态初始化是线程安全的,如 JLS 12.4.2 中所定义的那样:

Java 虚拟机的实现负责使用以下过程来处理同步和递归初始化...


注意:仅当可以使用某些静态方法而不使用 getInstance() 时才使用惰性实现才有用。在这种情况下,如果从未使用过,也会实例化 Singleton 类。


有关Java上的Singleton的完整描述,您可以查看我为Dzone撰写的一篇文章。

看看这个问题,了解一些关于你现在如何实现这一目标的想法,但请注意,TypeScript 2.0 将有私有构造函数,而且很快就会出现。目前,我建议编写以下代码...

class Singleton {
    private static instance: Singleton = new Singleton();
    // todo: mark as private when TS 2.0 comes out
    constructor() {
    }
    static getInstance() {
        return this.instance;
    }
}

。然后在 TypeScript 2.0 发布后将其更改为私有。

最新更新