Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 在泛型Typescript类中实现单例_Generics_Design Patterns_Typescript_Singleton - Fatal编程技术网

Generics 在泛型Typescript类中实现单例

Generics 在泛型Typescript类中实现单例,generics,design-patterns,typescript,singleton,Generics,Design Patterns,Typescript,Singleton,我有一个泛型类型,它将作为事件系统中事件的基类。我们期望这些参数是单例的,但它也是泛型的,这样子类就可以在事件触发时指定它们在回调中期望的参数类型 我所拥有的是这样的: export interface IEvent { } export interfact IEventArg { } export abstract class Event<TEvent extends IEvent, TEventArg extends IEventArg> implements IMessage

我有一个泛型类型,它将作为事件系统中事件的基类。我们期望这些参数是单例的,但它也是泛型的,这样子类就可以在事件触发时指定它们在回调中期望的参数类型

我所拥有的是这样的:

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);
导出接口事件{}
导出接口IEventArg{}
导出抽象类事件实现IMessageHandler{
私有静态s_实例:任意;
私有静态s_初始化:布尔;
构造函数(){
如果(!Event.s_正在初始化)
抛出新错误(“使用GetInstance方法获取该类实例。”);
}
公共静态GetInstance(类型:{new():T;}):TEvent{
如果(!s_实例){
s_i初始化=真;
s_实例=新类型();
s_i初始化=错误;
}
返回s_实例;
}
}
导出类SelectionEvent扩展事件{
...
}
var event=SelectionEvent.GetInstance(SelectionEvent);
这里有些事情我觉得奇怪,主要是因为打字语言的要求。GetInstance的参数似乎是必需的,因为TypeScript似乎不允许使用
var x=new TEvent()
。空接口有助于强制执行可以接受为泛型类型的内容

这里似乎不起作用的是静态变量和泛型类型的组合。GetInstance方法中的块是我想要做的,但显然它没有编译。我还担心静态实例变量不会在每个事件中创建一次,而是在每个事件实例中创建一次,因此会被覆盖

在C#中,泛型类的每个实例化(类型参数集)都有自己的静态成员集。这意味着您可以编写一个单例模式,其中一个实例用于
Foo
,另一个实例用于
Foo
,依此类推。这是可能的,因为泛型是在运行时显示的——运行时系统实际上知道泛型是什么,并且可以为每个类型实例化分配新对象。此外,类的静态端可以引用该类的类型参数(这是运行时语义的结果)

在TypeScript中,情况并非如此。每个类只有一个构造函数,泛型或其他。这意味着类的静态端无法“查看”泛型类型参数,因为对于具有静态成员
y
的任何类
X
,只有一个运行时插槽用于
X.y

类的单例模式通常不适合TypeScript;看见我认为您在这里有一些进展,因此如果没有关于您的用例的更多信息,我不能推荐任何具体的替代方案(可能会发布一个单独的问题)


此外,TypeScript中不应该有空接口。类型在结构上是比较的,因此任何两个空类型都是兼容的,并且您可以将任何内容分配给类型为空接口的变量。

好的,这就是我所关心的。我想我可能有一个替代实现的想法,我会尝试一下,并可能发布一个单独的问题。谢谢对于具有不同名称且没有类型参数的派生类(泛型单例)是否也存在相同的情况?我假设这是作为与派生类不同的类处理的。所以,当有一个泛型版本时,每次需要一个不同的单例时,都需要创建一个空的派生类,但可以重用泛型单例代码。不是说应该这样做,只是好奇这是否可行。