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

时间:2016-06-01 14:16:31

标签: javascript 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中有类似的东西吗?

3 个答案:

答案 0 :(得分:2)

这样的事情应该有效:

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的评论,静态初始化是线程安全的,如12.4.2中的JLS中所定义:

  

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

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

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

答案 1 :(得分:2)

我将从java部分开始,并将在@DavideLorenzoMARINO编写的内容上添加一个额外的内容,并且volatile keyword

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;
    }
}

如果你真的想确保它在多线程环境中有效,那么你甚至可能想要考虑" Double Checked Locking"的方法:

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中根本不使用一个类更有意义,它只是让事情变得更加冗长,你可以简单地说: / p>

namespace MySingleton {
    export interface MySingletonInstance {
        echo(value: string): string;
    }

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

答案 2 :(得分:0)

看看this issue有关如何实现这一目标的一些想法,但请注意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发布后将其更改为私有。