ค้นหาเว็บไซต์

javascript - วิธีสร้างคลาสที่ไม่สามารถสร้างอินสแตนซ์ภายนอกใน TypeScript ได้?


ในภาษา Java เรามีตัวสร้างแบบส่วนตัว

public class Singleton{
    private static volatile Singleton INSTANCE = null;
    private Singleton(){ }

    public static Singleton getInstance(){
        if(INSTANCE == null){
            synchronized(Singleton.class){
                if(INSTANCE == null){
                    INSTANCE = new Singleton();
                }
            }
        }
    return INSTANCE;
    }
}

ซึ่งทำให้คลาสไม่สามารถสร้างอินสแตนซ์นอกคลาสได้ มีสิ่งแบบนั้นใน TypeScript ไหม?

คำตอบ #1

ฉันจะเริ่มจากส่วนของจาวา และจะเพิ่มสิ่งหนึ่งเพิ่มเติมจากที่ @DavideLorenzoMARINO เขียน นั่นคือคีย์เวิร์ด volatile:

class MySingleton {
    private static volatile MySingleton instance;

    private MySingleton() {
        // do what ever
    }

    public static MySingleton getInstance() {
        if (MySingleton.instance == null) {
            MySingleton.instance = new MySingleton();
        }

        return MySingleton.instance;
    }
}

หากคุณต้องการให้แน่ใจว่าสิ่งนี้ทำงานได้ในสภาพแวดล้อมแบบมัลติเธรด คุณอาจต้องพิจารณาวิธีการที่เรียกว่า "Double Checked Locking" ด้วย:

class MySingleton {
    private static volatile MySingleton instance;

    private MySingleton() {
        // do what ever
    }

    public static MySingleton getInstance() {
        if (MySingleton.instance == null) {
            synchronized (MySingleton.class) {
                if (MySingleton.instance == null) {
                    MySingleton.instance = new MySingleton();
                }
            }
        }

        return MySingleton.instance;
    }
}

ส่วนของ TypeScript ผมคิดว่ารูปแบบนี้ไม่ค่อยเหมาะสมกับ TypeScript เพราะต่างจาก Java ในเวลารันไทม์ไม่มีอะไรป้องกันนักพัฒนาคนอื่นจากการสร้างอินสแตนซ์มากกว่าหนึ่งตัว

ถ้าคุณเชื่อถือผู้พัฒนาที่ทำงานกับโค้ดก็ถือว่าโอเค แต่ถ้าไม่เชื่อ ทำไมไม่ห่ออินสแตนซ์นั้นในโมดูล/เนมสเปซเพื่อซ่อนการทำงานล่ะ?

บางอย่างเช่น:

namespace MySingleton {
    class MySingletonInstance {
        echo(value: string): string {
            console.log(value);
            return value;
        }
    }

    export var instance = new MySingletonInstance();
}

แต่เนื่องจากคุณจะมีเพียงตัวอย่างเดียวของคลาสนี้ ดังนั้นฉันคิดว่าในจาวาสคริปต์จะสมเหตุสมผลกว่าที่จะไม่ใช้คลาสเลย มันทำให้โค้ดยืดยาวขึ้น และคุณสามารถทำได้ง่ายๆ ดังนี้:

namespace MySingleton {
    export interface MySingletonInstance {
        echo(value: string): string;
    }

    export var instance: MySingletonInstance = {
        echo: value => {
            console.log(value);
            return value;
        }
    }
}

คำตอบ #2

สิ่งที่ประมาณนั้นน่าจะใช้ได้:

class Singleton {

    private static _instance:Singleton = new Singleton();

    constructor() {
        if (Singleton._instance){
            throw new Error("Error: use getInstance()");
        }
        Singleton._instance = this;
    }

    public static getInstance():Singleton {
        return Singleton._instance;
    }

    ...
 }

นอกจากนี้ในภาษา Java ไม่จำเป็นต้องใช้การเริ่มต้นแบบ Lazy เนื่องจาก Singleton จะไม่ถูกสร้างขึ้นหากไม่ได้ใช้งาน วิธีที่ดีกว่า:

public class Singleton {
    private static Singleton INSTANCE = new Singleton();
    private Singleton() {}

    public Singleton getInstance(){
        return INSTANCE;
    }
}

เพื่อตอบความคิดเห็นของ Zhipeng การกำหนดค่าเริ่มต้นแบบคงที่ปลอดภัยสำหรับเธรด ตามที่กำหนดใน JLS ที่ 12.4.2:

การใช้งานของ Java Virtual Machine รับผิดชอบในการจัดการการซิงโครไนซ์และการเริ่มต้นแบบเรียกซ้ำ โดยใช้ขั้นตอนดังต่อไปนี้...

หมายเหตุ: การใช้การใช้งานแบบขี้เกียจมีประโยชน์ก็ต่อเมื่อสามารถใช้วิธีสแตติกบางอย่างโดยไม่ต้องใช้ getInstance() ในกรณีนี้ คลาส Singleton จะถูกสร้างอินสแตนซ์แม้ว่าจะไม่เคยถูกใช้งานก็ตาม

สำหรับคำอธิบายอย่างสมบูรณ์เกี่ยวกับ Singleton ใน Java คุณสามารถดูบทความที่ฉันเขียนสำหรับ Dzone ได้