Make decorator for singelton class — typescript

折月煮酒 提交于 2021-02-08 17:00:03

问题


I am building a project using VueJS with Typescript. I feel comfortable using services instead of any state management library like Vuex. But when writing services I have to always copy paste some code in each service class, to make it singelton as:

class MyService {
  private static Instance: MyService;
  public static getInstance() {
    if (!MyService.Instance) {
      MyService.Instance = new MyService();
    }
    return MyService.Instance;
  }
  private constructor() {}
}

I was thinking about the decorators, so my question is can we really get rid of this above code and use decorator, I tried some failed attempts as:

function service<T>(): T {
  const Instance: T | null = null;
  return !Instance ? new T() : Instance;
}

@service<MyService>()

or

function service(constructor: Function) {
  const Instance: MyService | null = null;
  return !Instance ? new MyService() : Instance;
}
@service

but these are not going to work. I am not sure that decorator will do the trick or not, other method may work here, but I don't have any idea, any suggestions?


回答1:


maybe you can try as follow

singletone.decorator.ts

const serviceList: any[] = [];

export function AsSingletone() {
    return (target: any): void  => {
        if(target.prototype.Instance) {
            return;
        }
        serviceList.push(target);
        Object.defineProperty(target, 'Instance', {
            get: function () {
                if (target.prototype.Instance) {
                    return target.prototype.Instance;
                }
                const instance = new target();
                target.prototype.Instance = instance;
                Object.defineProperty(target, 'Instance',
                  { get: function () { return instance; } }
                );
                return instance;
            }, configurable: true
        });
    };
}

export function registeredServiceList(): any[] {
    return serviceList;
}

service.ts

import { AsSingletone } from "./singletone.decorator";

@AsSingletone()
export class MyService {
  public static readonly Instance: MyService;
}

get access

console.log(MyService.Instance);

set throws exception

MyService.Instance = (new MyService() as any).Instance as MyService;

typescript playground example

VS Code snippet template, start typing - singl

"Singletone": {
    "prefix": ["singl"],
    "body": [
        "AsSingletone()\r",
        "export class ${0}Service {\r",
        "\tpublic static readonly Instance: ${0}Service;",
        "}"],
    "description": "Singletone service template"
  }



回答2:


what about this decorator?

export interface ServiceClassOptions {
    isSingleton: boolean;
}

/* eslint-disable space-before-function-paren */
export function ServiceClass(options: ServiceClassOptions) {
    return (constructor: any) => {
        console.log('from decorator', constructor.prototype.Instance);
        const original = constructor;

        const fun: any = (...args) => {
            if (options.isSingleton) {
                if (constructor.prototype.Instance) {
                    return constructor.prototype.Instance;
                } else {
                    const instance = new constructor(...args);
                    constructor.prototype.Instance = instance;

                    return instance;
                }
            }
            return new constructor(...args);
        };

        fun.prototype = original.prototype;

        return fun;
    };
}

decorator class as follows

@ServiceClass({
    isSingleton: true
})
export class AnyService {
}

then call new AnyService(); anytime you want will return same instance if isSingleton = true



来源:https://stackoverflow.com/questions/61582349/make-decorator-for-singelton-class-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!