Singletonów ogólnie radzą unikać, natomiast w jednym projekcie zauważyłem singleton, który w dodatku był specyficzny, inaczej pomyślany, niż to w przykładach pokazują. Zobaczmy.
Ok, więc to jest taki typowy singleton w TS:
class Lonely {
private static instance: Lonely;
private constructor() {}
static getInstance() {
if (this.instance) {
return this.instance;
}
this.instance = new Lonely();
return this.instance;
}
}
Prywatny konstruktor, statyczne publiczne getInstance. Gdyby jeszcze konstruktor musiał bazować na jakichś argumentach, to by się zrobiło createInstance i wtedy pola do popisu byśmy nie mieli.
Ale tutaj konstruktor jest pusty, więc ten przykład jest głupi (już pomijam, że w JS/TS dopisujemy do statycznych pól rzeczy przez this, nie np. static, mam nadzieję, że to nas nie dziwi, tak po prostu jest w JS).
Ok, to teraz zobaczmy taki interfejs i podpowiedź jest taka, że ten singleton będzie tylko ten interfejs implementował i pytanie jest, co możemy dzięki temu wywnioskować:
import ListItem from './ListItem'
interface List {
list: ListItem[],
load(): void,
save(): void,
clearList(): void,
addItem(itemObj: ListItem): void,
removeItem(id: string): void,
}
Wywnioskować możemy to, że klasa ma tylko jedno pole, list, które jest tablicą określonego typu, zapewne z wartością domyślną i także, posiada ta klasa metody, które służą do pracy na tej tablicy.
Zapewne zatem konstruktor będzie czymś takim, że z public static createInstance argumentów do private constructor przenosić nie będziemy.
To pytanie, po co nam w ogóle getInstance i createInstance? xD
No pytanie za sto punktów, a odpowiedź banalna:
export default class FullList implements List {
static instance: FullList = new FullList()
private constructor(private _list: ListItem[] = []) { }
get list(): ListItem[] {
return this._list
}
//(...)
}
Ha. Nic więcej nie trzeba. Prywatny konstruktor z domyślną wartością, pole statyczne instance, gdzie dajemy new FullList (korzystamy z konstruktora), plus implementacja metod z interfejsu (jedyną property, jaką jest list już zaimplementowaliśmy, nawet getter do niej).
I tyle. Potem po prostu importujemy klasę i odnosimy się do FullList.instance, nie musząc nigdzie tego tworzyć. Fajna sztuczka, nie znałem tego.
Więcej TSa niedługo.