답변:
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의 제약 조건이 사라지고 생성자가 숨겨지지 않기 때문에 다중 인스턴스화에 대한 보호 기능이 없다는 점에 대해 @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/
다음 접근 방식은 기존 클래스처럼 정확하게 사용할 수있는 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();
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 줄을 추가하여 "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 번 말하면 어떻게 되나요? 코드가 단일 인스턴스를 예약합니까?
어쩌면 제네릭을 사용하는 것이 어쩌면
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)
생성자에서 in을 귀찮게 합니까? 내보내기 전에 여러 인스턴스를 만든 경우 추가 예방 조치입니까?
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
어떤 특성이 있는가하면 값을 초기화하지 않는 한, 다음 타이프 라이터 컴파일러는 적합 발생합니다. 그렇기 _express
때문에 예제 클래스에 속성을 포함시킨 이유 는 값으로 초기화하지 않으면 나중에 생성자에서 할당하더라도 Typescript가 정의되지 않은 것으로 생각하기 때문입니다. 엄격 모드를 사용 중지하여 문제를 해결할 수 있지만 가능하면 바람직하지 않습니다. 생성자가 실제로 호출되기 때문에 다른 인스턴스를 수행 할 때마다 기술적으로 생성되지만 액세스 할 수는 없으므로이 방법에 대한 또 다른 단점이 있습니다. 이론적으로 메모리 누수가 발생할 수 있습니다.
이것은 아마도 타입 스크립트에서 싱글 톤을 만드는 가장 긴 프로세스 일지 모르지만 더 큰 응용 프로그램에서는 나에게 더 잘 맞는 것입니다.
먼저 "./utils/Singleton.ts"에 Singleton 클래스가 필요합니다 .
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();
}
Nice !, 이제 필요한 곳을 초기화하거나 가져옵니다 :
/// <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
그 클래스라면, 새로운 객체가 아닌 기존 객체를 얻습니다.
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();
정적 클래스에서는 모든 메소드와 변수도 정적이어야하므로 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
.
다른 옵션은 모듈에서 기호를 사용하는 것입니다. 이렇게하면 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의 대답과 달리 인터페이스를 적용 할 수 있습니다.
이 스레드를 수색하고 위의 모든 옵션을 가지고 놀았을 때-적절한 생성자로 만들 수있는 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()