回答:
TypeScriptのシングルトンクラスは、一般的にアンチパターンです。代わりに単に名前空間を使用できます。
class Singleton {
/* ... lots of singleton logic ... */
public someMethod() { ... }
}
// Using
var x = Singleton.getInstance();
x.someMethod();
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
export default new Singleton()
ですか?
TS 2.0以降、コンストラクターに可視性修飾子を定義できるようになりました。これで、他の言語で慣れているように、TypeScriptでシングルトンを実行できるようになりました。
与えられた例:
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;
TSの制約がなくなり、コンストラクターが隠されないため、生のコンパイルされたJavaScriptを使用してコードを記述した場合、複数のインスタンス化に対する保護がなくなることを指摘してくれて@Drenaiに感謝します。
私が見つけた最良の方法は:
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() );
https://codebelt.github.io/blog/typescript/typescript-singleton-pattern/
次のアプローチでは、従来のクラスとまったく同じように使用できるシングルトンクラスを作成します。
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();
new Class(...)
構文を実装する必要があります。
非常にシンプルに見える次のパターンがここに表示されないことに驚いています。
// shout.ts
class ShoutSingleton {
helloWorld() { return 'hi'; }
}
export let Shout = new ShoutSingleton();
使用法
import { Shout } from './shout';
Shout.helloWorld();
Shout
ただし、ユーザーが新しいクラスを作成することを
これにはクラス式を使用できます(1.6以降)。
var x = new (class {
/* ... lots of singleton logic ... */
public someMethod() { ... }
})();
または、クラスがそのタイプに内部的にアクセスする必要がある場合は名前
var x = new (class Singleton {
/* ... lots of singleton logic ... */
public someMethod(): Singleton { ... }
})();
別のオプションは、いくつかの静的メンバーを使用して、シングルトン内のローカルクラスを使用することです
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();
次の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
[編集]:メソッドではなくプロパティを通じてインスタンスを取得したい場合は、Alexの回答を使用します。
new MySingleton()
、5回を言いますか?あなたのコードは単一のインスタンスを予約しますか?
多分ジェネリックを使うとね
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;
}
使い方
ステップ1
class MapManager extends Singleton<MapManager>{
//do something
public init():void{ //do }
}
ステップ2
MapManager.Instance(MapManager).init();
関数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;
if (!this.instance)
ですか これは、エクスポートの前に複数のインスタンスを作成した場合の特別な予防策ですか?
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;
}
}
これには別の欠点があります。Singleton
プロパティにプロパティがある場合、値で初期化しない限り、Typescriptコンパイラはフィットをスローします。_express
プロパティを値で初期化しない限り、後でコンストラクターで割り当てたとしても、Typescriptはプロパティが定義されていないと考えるため、サンプルクラスにプロパティを含めたのはそのためです。これはストリクトモードを無効にすることで修正できますが、できればできません。また、このメソッドには別の欠点もあります。コンストラクタが実際に呼び出されるため、コンストラクタが実行されるたびに、別のインスタンスが技術的に作成されますが、アクセスできません。これにより、理論上、メモリリークが発生する可能性があります。
これはおそらくtypescriptでシングルトンを作成するのに最も長いプロセスですが、より大きなアプリケーションでは、私にとってよりうまくいったものです。
まず、"./ 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!.
このようにシングルトンを実行することの良い点は、typescriptクラスのすべての美しさを引き続き使用できることです。これにより、優れたインテリセンスが得られます。シングルトンロジックは何らかの方法で分離され、必要に応じて簡単に削除できます。
それに対する私の解決策:
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;
}
}
return Modal._instance
ます。この方法では、new
そのクラスの場合、新しいオブジェクトではなく、既存のオブジェクトを取得します。
Typescriptでは、必ずしもnew instance()
シングルトンの方法論に従う必要はありません。インポートされた、コンストラクターなしの静的クラスも同様に機能します。
考慮してください:
export class YourSingleton {
public static foo:bar;
public static initialise(_initVars:any):void {
YourSingleton.foo = _initvars.foo;
}
public static doThing():bar {
return YourSingleton.foo
}
}
クラスをインポートしYourSingleton.doThing()
て、他のクラスで参照できます。ただし、これは静的クラスであるため、コンストラクターがないため、通常intialise()
はシングルトンをインポートするクラスから呼び出されるメソッドを使用します。
import {YourSingleton} from 'singleton.ts';
YourSingleton.initialise(params);
let _result:bar = YourSingleton.doThing();
静的クラスで、すべてのメソッドおよび変数ニーズもそれほどの代わりに、静的であることを忘れないでくださいthis
、あなたが完全なクラス名を使用しますYourSingleton
。
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();
デモを見る
Instance
変数を追加する理由は何ですか?変数と関数をの直下に置くだけApp.Counter
です。
別のオプションは、モジュールでシンボルを使用することです。このようにして、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
これが最も簡単な方法です
class YourSingletoneClass {
private static instance: YourSingletoneClass;
private constructor(public ifYouHaveAnyParams: string) {
}
static getInstance() {
if(!YourSingletoneClass.instance) {
YourSingletoneClass.instance = new YourSingletoneClass('If you have any params');
}
return YourSingletoneClass.instance;
}
}
namespace MySingleton {
interface IMySingleton {
doSomething(): void;
}
class MySingleton implements IMySingleton {
private usePrivate() { }
doSomething() {
this.usePrivate();
}
}
export var Instance: IMySingleton = new MySingleton();
}
この方法では、Ryan Cavanaughの受け入れられた回答とは異なり、インターフェイスを適用できます。
このスレッドを精査し、上記のすべてのオプションを試した後、適切なコンストラクターで作成できるシングルトンで解決しました。
export default class Singleton {
private static _instance: Singleton
public static get instance(): Singleton {
return Singleton._instance
}
constructor(...args: string[]) {
// Initial setup
Singleton._instance = this
}
work() { /* example */ }
}
初期設定が必要です(main.ts
、またはindex.ts
)。これは、次の方法で簡単に実装できます。
new Singleton(/* PARAMS */)
次に、コードの任意の場所でを呼び出しSingleton.instnace
ます。この場合、完了するwork
には、Singleton.instance.work()