JavaScript事件系统是否违反LSP?
我问这个问题更多的是出于好奇,而不是真正关心它,但我一直想知道JavaScript事件系统是否违反了规则 通过调用,我们可以分派任意类型的,可能由注册的 如果我正确理解了LSP,这意味着JavaScript事件系统是否违反LSP?,javascript,dom-events,liskov-substitution-principle,Javascript,Dom Events,Liskov Substitution Principle,我问这个问题更多的是出于好奇,而不是真正关心它,但我一直想知道JavaScript事件系统是否违反了规则 通过调用,我们可以分派任意类型的,可能由注册的 如果我正确理解了LSP,这意味着anyEventListener.handleEvent(anyEvent)不应该失败。但是,通常情况并非如此,因为事件侦听器通常会使用专门的事件子类型的属性 在不支持泛型的类型化语言中,这种设计基本上需要将事件对象向下转换为事件监听器中的预期子类型 根据我的理解,上述设计可能被视为违反LSP。我是对的,还是在通
anyEventListener.handleEvent(anyEvent)
不应该失败。但是,通常情况并非如此,因为事件侦听器通常会使用专门的事件
子类型的属性
在不支持泛型的类型化语言中,这种设计基本上需要将事件
对象向下转换为事件监听器
中的预期子类型
根据我的理解,上述设计可能被视为违反LSP。我是对的,还是在通过注册侦听器时必须提供类型的简单事实可以防止LSP冲突
编辑:
虽然每个人似乎都在关注Event
子类没有违反LSP的事实,但实际上我担心EventListener
实现者会通过强化EventListener
接口的先决条件来违反LSP。void handleEvent(在evt事件中)
合同中没有任何内容告诉您,传递错误的事件
子类型可能会导致故障
在具有泛型的强类型语言中,该接口可以表示为EventListener
,以便实现者可以使契约显式化,例如SomeHandler实现EventListener
在JS中,显然没有实际的接口,但是事件处理程序仍然需要符合规范,并且该规范中没有任何内容允许处理程序判断它是否可以处理特定类型的事件
这不是一个真正的问题,因为监听器不需要自己调用,而是由注册了监听器并与特定类型关联的EventTarget
调用
我只是想知道根据该理论是否违反了LSP。我想知道,为了避免违反(如果从理论上考虑是这样的话),该合同是否需要类似于以下内容(尽管从实用主义角度看,它可能弊大于利):
不,JavaScript事件系统没有违反Liskov替换原则(LSP)
简单地说,LSP施加了以下约束“程序中的对象应可替换为其子类型的实例,而不改变该程序的正确性”
在JavaScript事件系统的特定示例中,EventListener
接口有一个函数签名,该签名需要一个事件
类型。实际上,这将通过子类型调用,例如KeyboardEvent
。这些子类型遵循LSP,因此,如果您提供在事件
接口上运行的handleEvent
实现,如果它被传递一个键盘事件
实例,它也将工作(即程序将是正确的)
然而,这完全是学术性的,因为在实践中,事件处理程序通常希望使用子类型上定义的属性或方法,例如KeyboardEvent.code
。在“强类型(*)语言(如C#)中,您可以在handleEvent
函数中从Event
强制转换为KeyboardEvent
。因为LSP定义了用子类型替换超级类型时所需的行为,所以从超级类型转换到子类型超出了LSP定义的行为范围
使用JavaScript时,您不需要为了使用KeyboardEvent
接口而强制转换,但是基本的基本原则适用
简言之,事件系统遵守LSP,但实际上您的handleEvent
实现将访问超类型方法,因此将超出LSP定义的范围
*
我在这里使用“强类型”这个词的意思非常松散 LSP的含义非常简单:子类型的行为不能违反其超类型行为。“超类型”行为是基于设计定义的,但一般来说,它只是意味着可以继续使用该对象,就像它是项目中任何位置的超类型一样
因此,在您的情况下,它应遵守以下规定:
(1) 键盘事件
可用于预期发生事件
的任何代码位置
(2) 对于Event
中的任何函数Event.func()
,相应的KeyboardEvent.func()
接受Event.func()的参数类型或其超类型,返回Event.func()的类型或其子类型,并仅抛出Event.func()
抛出的或其子类型
(3) 调用KeyboardEvent.func()
不会以Event.func()
无法发生的方式更改KeyboardEvent
的事件部分(数据成员)(历史规则)
LSP不需要的是关于KeyboardEvent
实现func()
的任何限制,只要它在概念上符合Event.func()
的要求。因此,它可以使用事件
未使用的函数和对象,在您的情况下,包括事件
超类型无法识别的自身对象的函数和对象
编辑问题:
替换原则要求子类型的行为(概念上)与它的超类型在任何需要超类型的地方的行为相同。
你的名字
interface EventListener {
void handleEvent(in Event evt);
}
interface EventListener {
bool handleEvent(in Event evt); //returns wheter or not the event could be handled
}