2015-12-11 2 views
1

У меня есть общий тип, который будет базовым классом для событий в системе событий. Мы ожидаем, что они будут одноточечными, но он также является общим, так что подклассы могут указывать тип аргумента, который они ожидают в обратном вызове, когда происходит событие.Реализация singleton в родовом классе Typcript

Что я должен выглядеть примерно так:

export interface IEvent { } 
export interfact IEventArg { } 

export abstract class Event<TEvent extends IEvent, TEventArg extends IEventArg> implements IMessageHandler { 

private static s_instance : any; 
private static s_isInitializing : boolean; 

constructor() { 
    if (!Event.s_isInitializing) 
     throw new Error ("Use the GetInstance method to get this class instance."); 
} 

public static GetInstance<TEvent extends IEvent, TEventArg extends IEventArg>(type: { new() : T; }) : TEvent { 
    if (!s_instance) { 
     s_isInitializing = true; 
     s_instance = new type(); 
     s_isInitializing = false; 
    } 

    return s_instance; 
} 
} 

export class SelectionEvent extends Event<SelectionEvent, EmptyEventArg> { 
... 
} 

var event = SelectionEvent.GetInstance(SelectionEvent); 

Есть некоторые вещи в здесь я считаю странным и есть в основном из-за требования машинописи языка. Аргумент для GetInstance кажется необходимым, потому что var x = new TEvent(), по-видимому, не допускается с помощью TypeScript. Пустые интерфейсы помогают обеспечить то, что может быть принято как общие типы.

Что здесь не работает, это сочетание статических переменных и общих типов. Блок в методе GetInstance - это то, что я хочу сделать, но, очевидно, он не компилируется. Я также обеспокоен тем, что статическая переменная экземпляра не будет создаваться один раз за Событие, а всего лишь один раз на экземпляр события и, таким образом, будет перезаписана.

Любое руководство здесь будет высоко оценено.

ответ

1

В C# каждый экземпляр (набор аргументов типа) универсального класса получает свой собственный набор статических членов. Это означает, что вы можете написать одноэлементный шаблон, в котором у вас есть один экземпляр для Foo<int>, другой для Foo<string> и т. Д. Это возможно, потому что generics - это манифест во время выполнения - система времени выполнения действительно знает, какие дженерики и могут выделять новые объекты для каждого типа экземпляра. Кроме того, статическая сторона класса может ссылаться на параметры типа этого класса (это следствие семантики времени выполнения).

В TypeScript это не тот случай. Существует только одна функция-конструктор для каждого класса, общий или другой. Это означает, что статическая сторона класса не может «видеть» параметры типового типа, потому что для любого класса X<T> со статическим членом y имеется только один слот времени выполнения для X.y.

Шаблон singleton для классов, как правило, плохо подходит для TypeScript; см. How to define Singleton in TypeScript. Я думаю, что здесь есть XY problem, поэтому я не могу рекомендовать какую-либо конкретную альтернативу без дополнительной информации о том, что ваш вариант использования (может быть, стоит задать отдельный вопрос).

Кроме того, вы должны никогда имеют пустые интерфейсы в TypeScript. Типы сравниваются structurally, поэтому любые два пустых типа совместимы, и вы можете назначить что-либо переменной, введенной как пустой интерфейс.

+0

ОК, это то, что меня беспокоило. Я думаю, что у меня может возникнуть идея альтернативной реализации, попробуем это и, возможно, опубликуем отдельный вопрос. Благодаря! –

+0

То же самое верно для производного класса (общего одноэлементного) с отдельным именем и аргументами типа? Я бы предположил, что это обрабатывается как отдельный класс из производного. Поэтому, имея общую версию, нужно будет создать пустой производный класс каждый раз, когда требуется отдельный синглтон, но может повторно использовать общий синглтон-код. не говоря, что это должно быть сделано просто любопытно, если это сработает. – ntziolis

Смежные вопросы