Wie man Singleton in TypeScript definiert
Was ist der beste und bequemste Weg, ein Singleton-Muster für eine Klasse in TypeScript zu implementieren? (Sowohl mit als auch ohne Lazy-Initialisierung).
Antwort #1
Seit TS 2.0 haben wir die Möglichkeit, Sichtbarkeitsmodifikatoren bei Konstruktoren zu definieren, sodass wir jetzt Singletons in TypeScript genauso machen können, wie wir es von anderen Sprachen gewohnt sind.
Beispiel gegeben:
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;
Danke @Drenai, dass du darauf hingewiesen hast, dass, wenn man Code mit dem rohen kompilierten JavaScript schreibt, man keinen Schutz gegen mehrfaches Instanziieren hat, da die Einschränkungen von TS verschwinden und der Konstruktor nicht verborgen wird.
Antwort #2
Singleton-Klassen in TypeScript sind im Allgemeinen ein Anti-Pattern. Sie können stattdessen einfach Namespaces verwenden.
Vergebliches Singleton-Muster
class Singleton {
/* ... lots of singleton logic ... */
public someMethod() { ... }
}
// Using
var x = Singleton.getInstance();
x.someMethod();
Namespace-Äquivalent
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
Antwort #3
Die beste Methode, die ich gefunden habe, ist:
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;
}
}
So verwenden Sie es:
var scoreManager = SingletonClass.getInstance();
scoreManager.setScore(10);
scoreManager.addPoints(1);
scoreManager.removePoints(2);
console.log( scoreManager.getScore() );
https://codebelt.github.io/blog/typescript/typescript-singleton-pattern/
Antwort #4
Der folgende Ansatz erstellt eine Singleton-Klasse, die genau wie eine herkömmliche Klasse verwendet werden kann:
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;
}
Jede new Singleton()-Operation wird dieselbe Instanz zurückgeben. Dies kann jedoch für den Benutzer unerwartet sein.
Das folgende Beispiel ist für den Benutzer transparenter, erfordert jedoch eine andere Verwendung:
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;
}
Verwendung: var obj=Singleton.getInstance();
Antwort #5
Ich bin überrascht, das folgende Muster hier nicht zu sehen, das eigentlich sehr einfach aussieht.
// shout.ts
class ShoutSingleton {
helloWorld() { return 'hi'; }
}
export let Shout = new ShoutSingleton();
Verwendung
import { Shout } from './shout';
Shout.helloWorld();
Antwort #6
Fügen Sie die folgenden 6 Zeilen zu jeder Klasse hinzu, um sie zu einem "Singleton" zu machen.
class MySingleton
{
private constructor(){ /* ... */}
private static _instance: MySingleton;
public static getInstance(): MySingleton
{
return this._instance || (this._instance = new this());
};
}
Testbeispiel:
var test = MySingleton.getInstance(); // will create the first instance
var test2 = MySingleton.getInstance(); // will return the first instance
alert(test === test2); // true
[Bearbeiten]: Verwenden Sie Alex' Antwort, wenn Sie die Instanz lieber über eine Eigenschaft als über eine Methode erhalten möchten.
[Bearbeiten 2]: Bonus: Wenn Sie ein Singleton aus Ihrer bestehenden Klasse in einer Zeile erzeugen möchten, können Sie diesen Klassen-Builder verwenden:
function AsSingleton<T extends new (...args: any[]) => any>(Aclass: T, ...args: ConstructorParameters<T>) {
return class extends Aclass {
static #instance: InstanceType<T>;
public static getInstance(): InstanceType<T> {
if (!this.#instance) {
this.#instance = new Aclass(...args);
}
return this.#instance;
}
} as Omit<T,"new"> & {getInstance:()=>InstanceType<T>};
}
Überprüfe diesen Ausschnitt auf ein Beispiel (sogar noch fortgeschrittener)
Verwendung: const AClassSingleton=AlsSingleton(AClass);
