javascript Typescript/ES6中的Singleton模式的正确方法是什么?

krcsximq  于 5个月前  发布在  Java
关注(0)|答案(3)|浏览(63)
class Foo{

}

var instance: Foo;
export function getFooInstance(){
    /* logic */
}

字符串

export class Foo{
    private static _instance;
    private constructor(){};
    public getInstance(){/* logic */}
}

// Use it like this
Foo.getInstance()


我想确保对象的示例只有一个方式?除了这个,还有其他建议吗?
Typescript Playground链接:

zvokhttg

zvokhttg1#

如果你想在类中使用getter,那么它需要是静态的:

export class Foo{
    private static _instance;
    private constructor(){};
    public static getInstance(){/* logic */}
}

字符串
问题是,虽然编译器会强制执行这种私有可见性,但在运行时,它仍然有可能绕过它,即使是无意的,例如有人直接从JavaScript使用它。
如果你使用模块/命名空间来强制它,那么你可以完全隐藏它:
使用模块:

export interface IFoo {}

class Foo implements IFoo {}

var instance: Foo;
export function getFooInstance(): IFoo {
    /* logic */

    return instance;
}


这是你的代码,我只是添加了IFoo接口(也是导出的),这样无论谁得到一个示例都会知道接口,但不知道类。
使用命名空间:

namespace Foo {
    export interface IFoo {}

    class FooClass implements IFoo {}

    const instance = new FooClass();
    export function getInstance(): IFoo {
        return instance;
    }
}

wydwbb8l

wydwbb8l2#

在JS和TypeScript中,如果你真的只想要一个示例,为什么不通过导出一个对象字面量来强制使用语言本身呢?

const Foo = {
  doSomething() {

  }
}

export default Foo;

字符串
IMO,这是遵循KISS,最少的样板,任何人都没有办法创建多个示例。
也就是说,你也可以直接导出函数。记住,模块本身可以作为单例。

export function doSomething() {
}


然后导入并想把它当作一个对象,你可以使用import *。如果函数真的属于对象,而不是所有的无状态静态函数,我更喜欢第一种方法。

import * as Foo from './Foo';

Foo.doSomething();

huwehgph

huwehgph3#

这取决于是否应该有机会为单例类创建一个新的示例。在最后一种情况下,getInstance可以省略,类构造函数可以充当单例工厂:

class Foo {
    private static _instance;
    constructor(...args) {
        if (Foo._instance) {
            return Foo._instance;
        }

        // if Foo extends non-singleton class or whatever,
        // super(...args);

        Foo._instance = this;
    };
}

字符串
同样的事情可以用装饰器为任意类做,比如:

@singleton
class Foo { ... }


由于存在一些typing problems with TypeScript decorators,因此应该在singleton装饰器中使用自定义继承代码,而不是Singleton extends Class

function singleton(Class) {
    function extend(sub, sup) {

        for (var prop in sup)
            if (sup.hasOwnProperty(prop))
                sub[prop] = sup[prop];

        function __() {
            this.constructor = sub;
        }

        __.prototype = sup.prototype;
        sub.prototype = new __();
    };

    const Singleton = <any>function (...args) {
        if (Singleton._instance) {
            return Singleton._instance;
        }

        Class.apply(this, args);

        Singleton._instance = this;
    }

    extend(Singleton, Class);

    return Singleton;
}


它可能会影响打字,但语法保持整洁。

相关问题