如何在 TypeScript 中定义单例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30174078/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to define Singleton in TypeScript
提问by maja
What is the best and most convenient way to implement a Singleton pattern for a class in TypeScript? (Both with and without lazy initialisation).
在 TypeScript 中为类实现单例模式的最佳和最方便的方法是什么?(有和没有延迟初始化)。
采纳答案by Ryan Cavanaugh
Singleton classes in TypeScript are generally an anti-pattern. You can simply use namespacesinstead.
TypeScript 中的单例类通常是一种反模式。您可以简单地使用命名空间。
Useless singleton pattern
无用的单例模式
class Singleton {
/* ... lots of singleton logic ... */
public someMethod() { ... }
}
// Using
var x = Singleton.getInstance();
x.someMethod();
Namespace equivalent
命名空间等价物
export namespace Singleton {
export function someMethod() { ... }
}
// Usage
import { SingletonInstance } from "path/to/Singleton";
SingletonInstance.someMethod();
var x = SingletonInstance; // If you need to alias it for some reason
回答by Alex
Since TS 2.0, we have the ability to define visibility modifiers on constructors, so now we can do singletons in TypeScript just like we are used to from other languages.
从 TS 2.0 开始,我们能够在构造函数上定义可见性修饰符,所以现在我们可以像在其他语言中一样在 TypeScript 中进行单例。
Example given:
给出的例子:
class MyClass
{
private static _instance: MyClass;
private constructor()
{
//...
}
public static get Instance()
{
// Do you need arguments? Make it a regular static method instead.
return this._instance || (this._instance = new this());
}
}
const myClassInstance = MyClass.Instance;
Thank you @Drenai for pointing out that if you write code using the raw compiled javascript you will not have protection against multiple instantiation, as the constraints of TS disappears and the constructor won't be hidden.
感谢@Drenai 指出,如果您使用原始编译的 javascript 编写代码,您将无法防止多次实例化,因为 TS 的约束消失并且构造函数不会被隐藏。
回答by codeBelt
The best way I have found is:
我发现的最好方法是:
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;
}
}
Here is how you use it:
以下是您如何使用它:
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/
http://www.codebelt.com/typescript/typescript-singleton-pattern/
回答by maja
The following approach creates a Singleton class that can be used exacly like a conventional class:
以下方法创建了一个可以像传统类一样使用的 Singleton 类:
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;
}
Each new Singleton()
operation will return the same instance. This can however be unexpected by the user.
每个new Singleton()
操作将返回相同的实例。然而,这可能是用户意想不到的。
The following example is more transparent to the user but requires a different usage:
以下示例对用户更透明,但需要不同的用法:
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;
}
Usage: var obj = Singleton.getInstance();
用法: var obj = Singleton.getInstance();
回答by Romain Bruckert
I am surprised not to see the following pattern here, which actually looks very simple.
我很惊讶在这里没有看到以下模式,实际上看起来很简单。
// shout.ts
class ShoutSingleton {
helloWorld() { return 'hi'; }
}
export let Shout = new ShoutSingleton();
Usage
用法
import { Shout } from './shout';
Shout.helloWorld();
回答by bingles
You can use class expressions for this (as of 1.6 I believe).
您可以为此使用类表达式(我相信从 1.6 开始)。
var x = new (class {
/* ... lots of singleton logic ... */
public someMethod() { ... }
})();
or with the name if your class needs to access its type internally
或者如果您的类需要在内部访问其类型,则使用名称
var x = new (class Singleton {
/* ... lots of singleton logic ... */
public someMethod(): Singleton { ... }
})();
Another option is to use a local class inside of your singleton using some static members
另一种选择是使用一些静态成员在单例内部使用本地类
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();
回答by Flavien Volken
Add the following 6 lines to any class to make it "Singleton".
将以下 6 行添加到任何类以使其成为“单例”。
class MySingleton
{
private constructor(){ /* ... */}
private static _instance: MySingleton;
public static getInstance(): MySingleton
{
return this._instance || (this._instance = new this());
};
}
var test = MySingleton.getInstance(); // will create the first instance
var test2 = MySingleton.getInstance(); // will return the first instance
alert(test === test2); // true
[Edit]: Use Alex answer if you prefer to get the instance through a property rather a method.
[编辑]:如果您更喜欢通过属性而不是方法获取实例,请使用 Alex 答案。
回答by sanye
i think maybe use generics be batter
我想也许使用泛型会更好
class Singleton<T>{
public static Instance<T>(c: {new(): T; }) : T{
if (this._instance == null){
this._instance = new c();
}
return this._instance;
}
private static _instance = null;
}
how to use
如何使用
step1
第1步
class MapManager extends Singleton<MapManager>{
//do something
public init():void{ //do }
}
step2
第2步
MapManager.Instance(MapManager).init();
回答by kenny
You can also make use of the function Object.Freeze(). Its simple and easy:
您还可以使用Object.Freeze()函数。它简单易行:
class Singleton {
instance: any = null;
data: any = {} // store data in here
constructor() {
if (!this.instance) {
this.instance = this;
}
return this.instance
}
}
const singleton: Singleton = new Singleton();
Object.freeze(singleton);
export default singleton;
回答by Eagerestwolf
I have found a new version of this that the Typescript compiler is totally okay with, and I think is better because it doesn't require calling a getInstance()
method constantly.
我发现了一个新版本,Typescript 编译器完全可以使用它,我认为它更好,因为它不需要getInstance()
不断调用方法。
import express, { Application } from 'express';
export class Singleton {
// Define your props here
private _express: Application = express();
private static _instance: Singleton;
constructor() {
if (Singleton._instance) {
return Singleton._instance;
}
// You don't have an instance, so continue
// Remember, to set the _instance property
Singleton._instance = this;
}
}
This does come with a different drawback. If your Singleton
does have any properties, then the Typescript compiler will throw a fit unless you initialize them with a value. That's why I included an _express
property in my example class because unless you initialize it with a value, even if you assign it later in the constructor, Typescript will think it hasn't been defined. This could be fixed by disabling strict mode, but I prefer not to if possible. There is also another downside to this method I should point out, because the constructor is actually getting called, each time it does another instance is technically created, but not accessible. This could, in theory, cause memory leaks.
这确实有一个不同的缺点。如果您Singleton
确实有任何属性,那么除非您使用值初始化它们,否则 Typescript 编译器将抛出一个合适的错误。这就是我_express
在我的示例类中包含一个属性的原因,因为除非你用一个值初始化它,即使你稍后在构造函数中分配它,Typescript 也会认为它没有被定义。这可以通过禁用严格模式来解决,但如果可能的话,我不想这样做。我应该指出这种方法还有另一个缺点,因为构造函数实际上是被调用的,每次它执行时,技术上都会创建另一个实例,但无法访问。理论上,这可能会导致内存泄漏。