Vyhledávání na webu

typescript - Je možné abstraktně oddělit singleton pattern od samotné třídy?


Prací s typescript/javascript jsem vytvořil kolekci singletonů.

Nicméně při pokusu o refaktoring a abstrakci implementace jsem se pokusil připravit třídu, která bude implementovat logiku singletonu a pro ně k rozšíření. To bylo očividně naivní z mé strany, protože situace vede k problémům s konstruktorem a zdá se být nerealizovatelná.

Takže moje otázka je, zda je možné elegantně aplikovat chování singletonu na kolekci tříd/objektů?

V následujícím kódu by bylo ze samotné čitelnosti hezké oddělit logiku singletonu. Dále bych chtěl konkrétně přinutit ostatní třídy v této kolekci, protože je přidávají přispěvatelé, aby je implementovaly jako singletony. Bylo by to trochu hezčí udělat jen prostřednictvím „zapojující“ nějakou abstraktní rozšířenou třídu nebo nějaký druh wrapperu.

class Car {
  /* Singleton Implementation Start */
  private static _instance: Car;

  private constructor() {}

  public static getInstance(): Car {
    if (!Car._instance) {
      Car._instance = new Car();
    }
    return Car._instance;
  }
  /* Singleton Implementation End */

  private _name = "Audi"
  private _color = 'red';
  private _maxSpeed = 150;

  drive(){
    console.log(`WOW! You are riding your cool ${this._color} ${this._name} at ${150} kmh!` )
  }

  paint(color: string){
    this._color = color;
  }
}

class Plane {
  /* Singleton Implementation Start */
  private static _instance: Plane;

  private constructor() {}

  public static getInstance(): Plane {
    if (!Plane._instance) {
      Plane._instance = new Plane();
    }
    return Plane._instance;
  }
  /* Singleton Implementation End */

  private _motors = 4;
  private _maxSpeed = 550;

  fly(){
    console.log(`WOW! You are flying your plane with roaring ${_motors} motors at ${150} kmh!` )
  }
}

Odpověď č. 1

Pokud vytvoříme tovární funkci, která přijímá generický typ:

function Singleton<T>() {
    return class Singleton {
        static instance: T; // must be public

        protected constructor() {}

        public static getInstance(): T {
            if (!this.instance) this.instance = new this() as T;

            return this.instance;
        }
    }
}

Pak můžeme rozšířit vrácenou třídu a poskytnout generiku jako samotnou třídu:

class Car extends Singleton<Car>() {
  private _name = "Audi"
  private _color = 'red';
  private _maxSpeed = 150;

  drive(){
    console.log(`WOW! You are riding your cool ${this._color} ${this._name} at ${150} kmh!` )
  }

  paint(color: string){
    this._color = color;
  }
}

Toto musí být provedeno funkcí, protože statické členy nemohou odkazovat na parametr typu třídy. Další nevýhodou je, že nemůžete mít žádné soukromé nebo chráněné členy.

Dětské hřiště

Související články