जवाबों:
टाइपस्क्रिप्ट में सिंगलटन कक्षाएं आमतौर पर एक विरोधी पैटर्न हैं। आप इसके बजाय बस नामस्थान का उपयोग कर सकते हैं ।
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()
?
टीएस 2.0 के बाद से, हमारे पास कंस्ट्रक्टर्स पर दृश्यता संशोधक को परिभाषित करने की क्षमता है , इसलिए अब हम टाइपस्क्रिप्ट में सिंगलेट्स कर सकते हैं जैसे हम अन्य भाषाओं से उपयोग करते हैं।
उदाहरण दिया गया:
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 धन्यवाद है कि यदि आप कच्चे संकलित जावास्क्रिप्ट का उपयोग करते हुए कोड लिखते हैं, तो आपको कई तात्कालिकता से सुरक्षा नहीं मिलेगी, क्योंकि TS की बाधाएं गायब हो जाती हैं और निर्माणकर्ता छिपा नहीं होगा।
सबसे अच्छा तरीका मैंने पाया है:
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
[संपादित करें] यदि आप किसी संपत्ति के बजाय एक विधि के माध्यम से उदाहरण प्राप्त करना पसंद करते हैं तो एलेक्स उत्तर का उपयोग करें।
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();
आप फ़ंक्शन ऑब्जेक्ट का उपयोग भी कर सकते हैं । फ़्रीज़ () । इसका सरल और आसान:
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)
तो कंस्ट्रक्टर में परेशान क्यों हों ? क्या आपने निर्यात से पहले कई उदाहरण बनाए हैं, तो यह सिर्फ एक अतिरिक्त सावधानी है?
मुझे इसका एक नया संस्करण मिला है कि टाइपस्क्रिप्ट कंपाइलर के साथ पूरी तरह से ठीक है, और मुझे लगता है कि यह बेहतर है क्योंकि इसे 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
पास कोई गुण है, तो टाइपस्क्रिप्ट कंपाइलर एक फिट फेंक देगा जब तक आप उन्हें एक मूल्य के साथ आरंभ नहीं करते। इसलिए मैंने _express
अपने उदाहरण वर्ग में एक संपत्ति शामिल की क्योंकि जब तक आप इसे एक मूल्य के साथ आरंभ नहीं करते हैं, भले ही आप इसे बाद में कंस्ट्रक्टर में असाइन करते हैं, तो टाइपस्क्रिप्ट को लगता है कि इसे परिभाषित नहीं किया गया है। यह सख्त मोड को अक्षम करके तय किया जा सकता है, लेकिन मैं संभव नहीं होने पर पसंद करता हूं। इस विधि का एक और नकारात्मक पहलू यह भी है कि मुझे इंगित करना चाहिए, क्योंकि निर्माणकर्ता को वास्तव में बुलाया जा रहा है, हर बार यह एक और उदाहरण तकनीकी रूप से निर्मित होता है, लेकिन सुलभ नहीं है। यह, सिद्धांत रूप में, स्मृति लीक का कारण बन सकता है।
यह शायद टाइपस्क्रिप्ट में एक सिंगलटन बनाने की सबसे लंबी प्रक्रिया है, लेकिन बड़े अनुप्रयोगों में वह है जिसने मेरे लिए बेहतर काम किया है।
सबसे पहले आप में एक सिंगलटन वर्ग की जरूरत है, के, मान लीजिए "./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!.
इस तरह से एकल करने के बारे में अच्छी बात यह है कि आप अभी भी टाइपस्क्रिप्ट कक्षाओं की सभी सुंदरता का उपयोग करते हैं, यह आपको अच्छा परिचय देता है, सिंगलटन तर्क किसी को अलग रखता है और यदि आवश्यक हो तो निकालना आसान है।
इसके लिए मेरा समाधान:
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
उस वर्ग को, आप मौजूदा वस्तु प्राप्त करते हैं, तो नया नहीं।
टाइपस्क्रिप्ट में, किसी को आवश्यक रूप से 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 का उपयोग करके अधिक पारंपरिक जावास्क्रिप्ट दृष्टिकोण के साथ करने का एक और तरीका है :
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
।
एक अन्य विकल्प अपने मॉड्यूल में प्रतीकों का उपयोग करना है। इस तरह आप अपनी कक्षा की सुरक्षा कर सकते हैं, भले ही आपके एपीआई का अंतिम उपयोगकर्ता सामान्य जावास्क्रिप्ट का उपयोग कर रहा हो:
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();
यदि उपयोगकर्ता आपकी संकलित एपीआई जेएस फ़ाइल का उपयोग कर रहा है, तो भी एक त्रुटि मिलेगी यदि वह मैन्युअल रूप से आपकी कक्षा को तुरंत करने की कोशिश करता है:
// 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();
}
इस तरह हम एक इंटरफ़ेस लागू कर सकते हैं, रेयान कैवानुग के स्वीकृत उत्तर के विपरीत।
इस धागे को खंगालने और उपरोक्त सभी विकल्पों के साथ खेलने के बाद - मैंने एक सिंगलटन के साथ समझौता किया जिसे उचित निर्माणकर्ताओं के साथ बनाया जा सकता है:
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()