如何在TypeScript中定义Singleton

在TypeScript中实现Singleton模式的最好和最方便的方法是什么? (有和没有懒惰的初始化)。

TypeScript中的单例类通常是反模式。 您可以简单地使用命名空间。

无用的单身模式

class Singleton { /* ... lots of singleton logic ... */ public someMethod() { ... } } // Using var x = Singleton.getInstance(); x.someMethod(); 

命名空间等效

 namespace Singleton { export function someMethod() { ... } } // Usage Singleton.someMethod(); var x = Singleton; // If you need to alias it for some reason 

自TS 2.0以来,我们可以在构造函数上定义可见性修饰符 ,所以现在我们可以像使用其他语言一样在TypeScript中完成单例。

给出的例子:

 class MyClass { private static _instance: MyClass; private constructor() { //... } public static get Instance() { // Do you need arguments? Make it a regular method instead. return this._instance || (this._instance = new this()); } } const myClassInstance = MyClass.Instance; 

我发现的最好的方法是:

 class SingletonClass { private static _instance:SingletonClass = new SingletonClass(); private _score:number = 0; constructor() { if(SingletonClass._instance){ throw new Error("Error: Instantiation failed: Use SingletonClass.getInstance() instead of new."); } SingletonClass._instance = this; } public static getInstance():SingletonClass { return SingletonClass._instance; } public setScore(value:number):void { this._score = value; } public getScore():number { return this._score; } public addPoints(value:number):void { this._score += value; } public removePoints(value:number):void { this._score -= value; } } 

这里是你如何使用它:

 var scoreManager = SingletonClass.getInstance(); scoreManager.setScore(10); scoreManager.addPoints(1); scoreManager.removePoints(2); console.log( scoreManager.getScore() ); 

http://www.codebelt.com/typescript/typescript-singleton-pattern/

下面的方法创build一个可以象传统类一样使用的单例类:

 class Singleton { private static instance: Singleton; //Assign "new Singleton()" here to avoid lazy initialisation constructor() { if (Singleton.instance) { return Singleton.instance; } this. member = 0; Singleton.instance = this; } member: number; } 

每个new Singleton()操作将返回相同的实例。 这可能是用户意想不到的。

以下示例对用户更加透明,但需要不同的用法:

 class Singleton { private static instance: Singleton; //Assign "new Singleton()" here to avoid lazy initialisation constructor() { if (Singleton.instance) { throw new Error("Error - use Singleton.getInstance()"); } this.member = 0; } static getInstance(): Singleton { Singleton.instance = Singleton.instance || new Singleton(); return Singleton.instance; } member: number; } 

用法: var obj = Singleton.getInstance();

你可以使用类expression式(我相信从1.6)。

 var x = new (class { /* ... lots of singleton logic ... */ public someMethod() { ... } })(); 

或者如果你的类需要在内部访问它的types的名称

 var x = new (class Singleton { /* ... lots of singleton logic ... */ public someMethod(): Singleton { ... } })(); 

另一种select是使用一些静态成员在你的单例中使用本地类

 class Singleton { private static _instance; public static get instance() { class InternalSingleton { someMethod() { } //more singleton logic } if(!Singleton._instance) { Singleton._instance = new InternalSingleton(); } return <InternalSingleton>Singleton._instance; } } var x = Singleton.instance; x.someMethod(); 

我很惊讶,看不到下面的模式,这实际上看起来很简单。

 // shout.ts class ShoutSingleton { helloWorld() { return 'hi'; } } export let Shout = new ShoutSingleton(); 

用法

 import { Shout } from './shout'; Shout.helloWorld(); 

将以下5行添加到任何类中,使其成为“Singleton”。 如果你喜欢通过属性而不是方法获取实例,请使用Alex答案。

 class MySingleton { private static _instance:MySingleton; public static getInstance():MySingleton { return MySingleton._instance||(MySingleton._instance = new MySingleton()); }; } 

testing例子:

 var test = MySingleton.getInstance(); // will create the first instance var test2 = MySingleton.getInstance(); // will return the first instance alert(test === test2); // true 

这可能是打字稿中单身人士最长的一个过程,但是在较大的应用程序中,这对我来说是一个更好的工作。

首先你需要一个Singleton类,比方说, “./utils/Singleton.ts”

 module utils { export class Singleton { private _initialized: boolean; private _setSingleton(): void { if (this._initialized) throw Error('Singleton is already initialized.'); this._initialized = true; } get setSingleton() { return this._setSingleton; } } } 

现在想象你需要一个路由器单身“./navigation/Router.ts”

 /// <reference path="../utils/Singleton.ts" /> module navigation { class RouterClass extends utils.Singleton { // NOTICE RouterClass extends from utils.Singleton // and that it isn't exportable. private _init(): void { // This method will be your "construtor" now, // to avoid double initialization, don't forget // the parent class setSingleton method!. this.setSingleton(); // Initialization stuff. } // Expose _init method. get init { return this.init; } } // THIS IS IT!! Export a new RouterClass, that no // one can instantiate ever again!. export var Router: RouterClass = new RouterClass(); } 

尼斯!,现在初始化或导入你需要的任何地方:

 /// <reference path="./navigation/Router.ts" /> import router = navigation.Router; router.init(); router.init(); // Throws error!. 

这样做单身人士的好处是,你仍然使用打字稿类的所有美丽,它给你很好的intellisense,单身逻辑保持分开,很容易删除,如果需要的话。

这是另一种使用IFFE的更传统的JavaScript方法:

 module App.Counter { export var Instance = (() => { var i = 0; return { increment: (): void => { i++; }, getCount: (): number => { return i; } } })(); } module App { export function countStuff() { App.Counter.Instance.increment(); App.Counter.Instance.increment(); alert(App.Counter.Instance.getCount()); } } App.countStuff(); 

查看演示

另一种select是在模块中使用符号。 这样你可以保护你的类,如果你的API的最终用户使用正常的Javascript:

 let _instance = Symbol(); export default class Singleton { constructor(singletonToken) { if (singletonToken !== _instance) { throw new Error("Cannot instantiate directly."); } //Init your class } static get instance() { return this[_instance] || (this[_instance] = new Singleton(_singleton)) } public myMethod():string { return "foo"; } } 

用法:

 var str:string = Singleton.instance.myFoo(); 

如果用户正在使用编译的API js文件,如果他尝试手动实例化类,也会出错:

 // PLAIN JAVASCRIPT: var instance = new Singleton(); //Error the argument singletonToken !== _instance symbol 

我的解决scheme是:

 export default class Modal { private static _instance : Modal = new Modal(); constructor () { if (Modal._instance) throw new Error("Use Modal.instance"); Modal._instance = this; } static get instance () { return Modal._instance; } } 
 namespace MySingleton { interface IMySingleton { doSomething(): void; } class MySingleton implements IMySingleton { private usePrivate() { } doSomething() { this.usePrivate(); } } export var Instance: IMySingleton = new MySingleton(); } 

这种方式我们可以应用一个接口,不像Ryan Cavanaugh公认的答案。