วิธีกำหนด Singleton ใน TypeScript


128

วิธีใดที่ดีที่สุดและสะดวกที่สุดในการนำรูปแบบ Singleton ไปใช้กับคลาสใน TypeScript คืออะไร (ทั้งที่มีและไม่มีการเริ่มต้นแบบขี้เกียจ)

คำตอบ:


87

คลาส Singleton ใน 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

55
คงจะดีไม่น้อยที่ตอนนี้ทำไมซิงเกิลตันถึงถือเป็นรูปแบบการต่อต้าน? พิจารณาแนวทางนี้codebelt.com/typescript/typescript-singleton-pattern
วิกเตอร์

21
ฉันต้องการทราบว่าเหตุใด Singletons ใน TypeScript จึงถูกพิจารณาว่าเป็นรูปแบบการต่อต้านด้วย และถ้ามันไม่มีพารามิเตอร์ตัวสร้างทำไมexport default new Singleton()ล่ะ?
emzero

23
โซลูชันเนมสเปซดูเหมือนคลาสแบบคงที่ไม่ใช่ซิงเกิลตัน
Mihai Răducanu

6
มันทำงานเหมือนกัน ใน C # คุณไม่สามารถส่งผ่านคลาสคงที่ราวกับว่ามันเป็นค่า (เช่นราวกับว่ามันเป็นอินสแตนซ์ของคลาสซิงเกิลตัน) ซึ่ง จำกัด ประโยชน์ของมัน ใน TypeScript คุณสามารถส่งเนมสเปซไปรอบ ๆ เช่นอินสแตนซ์ นั่นเป็นเหตุผลที่คุณไม่จำเป็นต้องเรียนแบบซิงเกิลตัน
Ryan Cavanaugh

13
ข้อ จำกัด ของการใช้เนมสเปซเป็นซิงเกิลตันคือไม่สามารถใช้อินเทอร์เฟซได้ (ตามความรู้ของฉัน) คุณจะเห็นด้วยกับเรื่องนี้หรือไม่ @ryan
Gabe O'Leary

182

ตั้งแต่ TS 2.0 เรามีความสามารถในการกำหนดตัวปรับการมองเห็นบนตัวสร้างดังนั้นตอนนี้เราสามารถทำ singletons ใน 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;

ขอบคุณ @Drenai ที่ชี้ให้เห็นว่าหากคุณเขียนโค้ดโดยใช้ JavaScript ที่คอมไพล์แล้วคุณจะไม่มีการป้องกันจากการสร้างอินสแตนซ์หลายรายการเนื่องจากข้อ จำกัด ของ TS หายไปและตัวสร้างจะไม่ถูกซ่อน


2
ผู้สร้างอาจเป็นส่วนตัว?
ผู้เชี่ยวชาญต้องการ

2
@Expertwannabe พร้อมใช้งานแล้วใน TS 2.0: github.com/Microsoft/TypeScript/wiki/…
Alex

3
นี่คือคำตอบที่ฉันต้องการ! ขอบคุณ.
Martin Majewski

1
fyi สาเหตุของอินสแตนซ์หลายรายการคือความละเอียดโมดูลโหนดเข้ามาขวางทาง ดังนั้นหากคุณกำลังสร้างซิงเกิลตันในโหนดตรวจสอบให้แน่ใจว่าได้พิจารณาแล้ว ฉันลงเอยด้วยการสร้างโฟลเดอร์ node_modules ภายใต้ไดเร็กทอรี src ของฉันและวางซิงเกิลตันไว้ที่นั่น
webteckie

3
@KimchiMan หากเคยใช้โปรเจ็กต์ในสภาพแวดล้อมที่ไม่ใช่ typescript เช่นอิมพอร์ตไปยังโปรเจ็กต์ JS คลาสจะไม่มีการป้องกันการสร้างอินสแตนซ์เพิ่มเติม ใช้งานได้ในสภาพแวดล้อม TS ที่บริสุทธิ์เท่านั้น แต่ไม่ใช่สำหรับการพัฒนาไลบรารี JS
Drenai

39

วิธีที่ดีที่สุดที่ฉันพบคือ:

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/


3
ทำไมไม่ทำให้ตัวสร้างเป็นแบบส่วนตัว
Phil Mander

4
ฉันคิดว่าโพสต์มาก่อนความสามารถในการมีคอนสตรัคเตอร์ส่วนตัวใน TS github.com/Microsoft/TypeScript/issues/2341
Trevor

ฉันชอบคำตอบนี้ คอนสตรัคเตอร์ส่วนตัวนั้นยอดเยี่ยมในระหว่างการพัฒนา แต่หากนำเข้าโมดูล TS แบบ Transpiled เข้าสู่สภาพแวดล้อม JS ก็ยังสามารถเข้าถึงตัวสร้างได้ ด้วยวิธีนี้เกือบจะได้รับการป้องกันจากการใช้ในทางที่ผิด .... เว้นแต่ SingletonClass ['_ instance'] ถูกตั้งค่าเป็น null / ไม่ได้กำหนด
Drenai

ลิงค์เสีย ฉันคิดว่านี่เป็นลิงค์จริง: codebelt.github.io/blog/typescript/typescript-singleton-pattern
El Asiduo

24

แนวทางต่อไปนี้จะสร้างคลาส 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;
}

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();


1
นี่คือแนวทางที่ควรดำเนินการ หากมี 1 สิ่งที่ฉันไม่เห็นด้วยกับ The Gang of Four on - และอาจเป็นเพียง 1 - The Singleton Pattern บางที C / ++ อาจขัดขวางไม่ให้ออกแบบด้วยวิธีนี้ แต่ถ้าคุณถามฉันรหัสไคลเอ็นต์ไม่ควรรู้หรือสนใจว่าเป็น Singleton หรือไม่ ไคลเอ็นต์ควรใช้new Class(...)ไวยากรณ์
Cody

16

ฉันแปลกใจที่ไม่เห็นรูปแบบต่อไปนี้ซึ่งจริงๆแล้วมันดูเรียบง่ายมาก

// shout.ts
class ShoutSingleton {
  helloWorld() { return 'hi'; }
}

export let Shout = new ShoutSingleton();

การใช้

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

ฉันได้รับข้อความแสดงข้อผิดพลาดต่อไปนี้: ตัวแปรที่ส่งออก 'Shout' มีหรือกำลังใช้ชื่อส่วนตัว 'ShoutSingleton'
Twois

3
คุณต้องส่งออกคลาส 'ShoutSingleton' ด้วยและข้อผิดพลาดจะหายไป
Twois

ใช่ฉันประหลาดใจเช่นกัน ทำไมถึงต้องรำคาญกับชั้นเรียน? Singletons ควรจะซ่อนการทำงานภายในของพวกเขา ทำไมไม่เพียงแค่ส่งออกฟังก์ชัน helloWorld?
Oleg Dulin

ดูปัญหา github นี้สำหรับข้อมูลเพิ่มเติม: github.com/Microsoft/TypeScript/issues/6307
Ore4444

5
เดาว่าไม่มีอะไรหยุดผู้ใช้จากการสร้างShoutคลาสใหม่ได้
dalore

7

คุณสามารถใช้นิพจน์คลาสสำหรับสิ่งนี้ (ตั้งแต่ 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();

7

เพิ่ม 6 บรรทัดต่อไปนี้ในคลาสใดก็ได้เพื่อให้เป็น "Singleton"

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 ครั้ง? รหัสของคุณสงวนอินสแตนซ์เดียวหรือไม่
Hlawuleka MAS

คุณไม่ควรใช้ "ใหม่": ตามที่อเล็กซ์เขียนตัวสร้างควรเป็น "ส่วนตัว" ป้องกันไม่ให้ทำ "MySingleton ใหม่ ()" การใช้งานที่เหมาะสมคือการรับอินสแตนซ์โดยใช้ MySingleton.getInstance () AKAIK ไม่มีตัวสร้าง (เหมือนในตัวอย่างของฉัน) = ตัวสร้างที่ว่างเปล่าสาธารณะ
Flavien Volken

"คุณไม่ควรใช้" ใหม่ "- ตรงประเด็นของฉัน:" แต่การนำไปใช้ของคุณป้องกันไม่ให้ฉันทำเช่นนั้นได้อย่างไร ฉันไม่เห็นที่ไหนที่คุณมีคอนสตรัคเตอร์ส่วนตัวในชั้นเรียนของคุณ?
Hlawuleka MAS

@HlawulekaMAS ฉันไม่ได้ ... ดังนั้นฉันจึงแก้ไขคำตอบโปรดทราบว่าตัวสร้างส่วนตัวไม่สามารถทำได้ก่อน TS 2.0 (เช่นในเวลาที่ฉันเขียนคำตอบก่อน)
Flavien Volken

"เช่นในเวลาที่ฉันเขียนคำตอบก่อน" - เข้าท่า เย็น.
Hlawuleka MAS

3

ฉันคิดว่าอาจจะใช้ชื่อสามัญเป็นแป้ง

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();

3

นอกจากนี้คุณยังสามารถใช้ฟังก์ชั่น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;

Kenny เป็นจุดที่ดีในการหยุด () แต่สองบันทึก: (1) หลังจากที่คุณหยุด (singleton) คุณยังสามารถแก้ไข singleton.data ได้ .. คุณไม่สามารถเพิ่มแอตทริบิวต์อื่น ๆ (เช่น data2) ได้ แต่จุดนั้นคือการหยุด ( ) ไม่ได้หยุดนิ่งลึก :) และ (2) คลาส Singleton ของคุณอนุญาตให้สร้างมากกว่าหนึ่งอินสแตนซ์ (เช่น obj1 = new Singleton (); obj2 = new Singleton ();) ดังนั้น Singleton ของคุณจึงไม่ใช่ Singleton
:)

หากคุณนำเข้าคลาส Singleton ในไฟล์อื่นคุณจะได้รับอินสแตนซ์เดียวกันเสมอและข้อมูลใน 'data' จะสอดคล้องกันระหว่างการนำเข้าอื่น ๆ ทั้งหมด นั่นสำหรับฉันซิงเกิลตัน การหยุดการตรวจสอบให้แน่ใจว่าอินสแตนซ์ Singleton ที่ส่งออกถูกสร้างขึ้นเพียงครั้งเดียว
kenny

Kenny (1) หากคุณนำเข้าชั้นเรียนในไฟล์อื่นคุณจะไม่ได้รับอินสแตนซ์ โดยการนำเข้าคุณเพียงแค่นำคำจำกัดความของคลาสมาอยู่ในขอบเขตเพื่อให้คุณสามารถสร้างอินสแตนซ์ใหม่ได้ จากนั้นคุณสามารถสร้าง> 1 อินสแตนซ์ของคลาสที่กำหนดไม่ว่าจะเป็นไฟล์เดียวหรือหลายไฟล์ซึ่งขัดต่อจุดประสงค์ทั้งหมดของแนวคิดแบบซิงเกิลตัน (2) จากเอกสาร: Object.freeze () วิธีการหยุดวัตถุ ไม่สามารถเปลี่ยนแปลงวัตถุที่ถูกแช่แข็งได้อีกต่อไป การแช่แข็งวัตถุจะป้องกันไม่ให้เพิ่มคุณสมบัติใหม่เข้าไป (ท้ายใบเสนอราคา) ซึ่งหมายถึงการหยุด () ไม่ได้หยุดคุณจากการสร้างวัตถุหลายชิ้น
Dmitry Shevkoplyas

จริง แต่ในกรณีนี้จะเป็นเพราะสมาชิกที่ส่งออกเป็นอินสแตนซ์อยู่แล้ว และอินสแตนซ์จะเก็บข้อมูล หากคุณใส่การส่งออกในคลาสด้วยแสดงว่าคุณถูกต้องและคุณสามารถสร้างหลายอินสแตนซ์ได้
kenny

@kenny ถ้าคุณรู้ว่าคุณกำลังจะส่งออกอินสแตนซ์ทำไมต้องกังวลกับif (!this.instance)ตัวสร้าง? นั่นเป็นเพียงข้อควรระวังเพิ่มเติมในกรณีที่คุณสร้างหลายอินสแตนซ์ก่อนการส่งออกหรือไม่
Alex

2

ฉันพบเวอร์ชันใหม่ของสิ่งนี้ที่คอมไพเลอร์ 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 จะคิดว่ามันไม่ได้กำหนดไว้ สิ่งนี้สามารถแก้ไขได้โดยการปิดโหมดเข้มงวด แต่ฉันไม่ต้องการถ้าเป็นไปได้ นอกจากนี้ยังมีข้อเสียอีกประการหนึ่งของวิธีนี้ที่ฉันควรชี้ให้เห็นเนื่องจากตัวสร้างถูกเรียกจริง ๆ ทุกครั้งที่สร้างอินสแตนซ์อื่นจะถูกสร้างขึ้นในทางเทคนิค แต่ไม่สามารถเข้าถึงได้ ในทางทฤษฎีอาจทำให้หน่วยความจำรั่วไหล


1

นี่อาจเป็นกระบวนการที่ยาวที่สุดในการสร้างซิงเกิลตันในรูปแบบตัวพิมพ์ แต่ในแอปพลิเคชันขนาดใหญ่เป็นกระบวนการที่ทำงานได้ดีกว่าสำหรับฉัน

ก่อนอื่นคุณต้องมีคลาส 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; }
    }
}

ลองนึกดูว่าคุณต้องการ Router singleton "./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 ทั้งหมดมันให้ intellisense ที่ดีตรรกะของ singleton ช่วยแยกบางส่วนและง่ายต่อการลบออกหากจำเป็น


1

ทางออกของฉันสำหรับมัน:

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;
    }
}

1
ใน Constructor return Modal._instanceให้แทนของข้อยกเว้นที่คุณสามารถ ด้วยวิธีนี้ถ้าคุณเป็นnewคลาสนั้นคุณจะได้รับวัตถุที่มีอยู่ไม่ใช่ของใหม่
Mihai Răducanu

1

ใน typescript ไม่จำเป็นต้องทำตามnew instance()วิธีการของ Singleton คลาสคงที่ที่นำเข้าและไม่ใช้ตัวสร้างสามารถทำงานได้อย่างเท่าเทียมกัน

พิจารณา:

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()วิธีการที่เรียกจากคลาสที่นำเข้า Singleton:

import {YourSingleton} from 'singleton.ts';

YourSingleton.initialise(params);
let _result:bar = YourSingleton.doThing();

อย่าลืมว่าในระดับคงที่, ทุกวิธีและความต้องการของตัวแปรที่จะยังคงที่ดังนั้นแทนที่จะคุณจะใช้ชื่อชั้นเต็มรูปแบบthisYourSingleton


0

นี่เป็นอีกวิธีหนึ่งในการใช้วิธีการใช้จาวาสคริปต์แบบธรรมดาโดยใช้IFFE :

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ตัวแปรคืออะไร? คุณ coukd เพียงแค่ใส่ตัวแปรและฟังก์ชันไว้App.Counterข้างใต้
fyaa

@fyaa ใช่คุณสามารถ แต่ตัวแปรและฟังก์ชั่นโดยตรงภายใต้ App.Counter แต่ฉันคิดว่าวิธีนี้ดีกว่าที่จะสอดรับกับรูปแบบเดี่ยวen.wikipedia.org/wiki/Singleton_pattern
JesperA

0

อีกทางเลือกหนึ่งคือการใช้ Symbols ในโมดูลของคุณ ด้วยวิธีนี้คุณสามารถปกป้องชั้นเรียนของคุณได้เช่นกันหากผู้ใช้ขั้นสุดท้ายของ 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

0

ไม่ใช่ซิงเกิลตันที่บริสุทธิ์ (การเริ่มต้นอาจไม่น่าเกียจ) แต่รูปแบบที่คล้ายกันด้วยความช่วยเหลือของnamespaces

namespace MyClass
{
    class _MyClass
    {
    ...
    }
    export const instance: _MyClass = new _MyClass();
}

การเข้าถึงวัตถุของ Singleton:

MyClass.instance

0

นี่เป็นวิธีที่ง่ายที่สุด

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;
  }
}

-1
namespace MySingleton {
  interface IMySingleton {
      doSomething(): void;
  }
  class MySingleton implements IMySingleton {
      private usePrivate() { }
      doSomething() {
          this.usePrivate();
      }
  }
  export var Instance: IMySingleton = new MySingleton();
}

วิธีนี้เราสามารถใช้อินเทอร์เฟซซึ่งแตกต่างจากคำตอบที่ยอมรับของ Ryan Cavanaugh


-1

หลังจากกำจัดสิ่งสกปรกบนเธรดนี้และเล่นกับตัวเลือกทั้งหมดข้างต้น - ฉันตัดสินด้วย Singleton ที่สามารถสร้างด้วยตัวสร้างที่เหมาะสม:

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()


เหตุใดจึงมีคนลงคะแนนคำตอบโดยไม่แสดงความคิดเห็นเกี่ยวกับการปรับปรุง เราคือชุมชน
TheGeekZn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.