gpt4 book ai didi

javascript - JavaScript 事件系统是否违反了 LSP?

转载 作者:可可西里 更新时间:2023-11-01 01:33:59 27 4
gpt4 key购买 nike

我更多是出于好奇而不是真正关心它 ,但我一直想知道 JavaScript 事件系统是否违反了 Liskov substitution principle (LSP)或不。

调用 EventTarget.dispatchEvent ,我们可以发送 Event 可能由已注册的 EventListener 处理的任意类型.

interface EventListener {
void handleEvent(in Event evt);
}

如果我正确理解 LSP,则意味着 anyEventListener.handleEvent(anyEvent)不应该失败。但是,通常情况并非如此,因为事件监听器通常会使用专用 Event 的属性。子类型。

在不支持泛型的类型化语言中,该设计基本上需要向下转换 Event EventListener 中预期的子类型的对象.

据我了解,上述设计可被视为违反 LSP。我是正确的还是必须提供 type 的简单事实?通过 EventTarget.addEventListener 注册监听器时防止 LSP 违规?

编辑:

虽然每个人似乎都在关注 Event子类没有违反 LSP,我实际上担心 EventListener实现者会通过加强 EventListener 的先决条件来违反 LSP。的界面。 void handleEvent(in Event evt) 中没有任何内容契约(Contract)告诉你,传递错误的东西可能会破坏 Event子类型。

在具有泛型的强类型语言中,接口(interface)可以表示为 EventListener<T extends Event>以便实现者可以使契约(Contract)明确,例如 SomeHandler implements EventListener<SomeEvent> .

在 JS 中显然没有实际的接口(interface),但事件处理程序仍然需要符合规范,并且该规范中没有任何内容允许处理程序判断它是否可以处理特定类型的事件。

这不是一个真正的问题,因为监听器不应该被自己调用,而是由 EventTarget 调用。注册地址和 与特定类型相关 .

我只是对根据理论是否违反 LSP 感兴趣。 我想知道是否要避免违反(如果从理论上考虑),契约(Contract)需要类似于以下内容(即使它在实用主义方面可能做得比好坏):
interface EventListener {
bool handleEvent(in Event evt); //returns wheter or not the event could be handled
}

最佳答案

LSP 的含义很简单:子类型不能以违反其父类(super class)型行为的方式行事。这种“父类(super class)型”行为基于设计定义,但总的来说,它只是意味着可以继续使用该对象,就好像它是项目中任何地方的父类(super class)型一样。

因此,就您而言,它应遵守以下规定:

(1) 一个KeyboardEvent可以在代码的任何位置使用 Event是期待;

(2) 对于任何函数Event.func()Event ,对应的KeyboardEvent.func()接受 Event.func() 的类型的参数或其父类(super class)型,返回 Event.Func() 的类型或其子类型,并且只抛出 Event.func() throws 或其子类型;

(3) Event KeyboardEvent 的一部分(数据成员)调用 KeyboardEvent.func() 不会改变以 Event.func() 不可能发生的方式(历史规则)。

什么是不是 LSP 要求的,是关于 KeyboardEvent 的任何限制吗? func()的实现,只要它确实如此,从概念上讲,Event.func()应该。因此,它可以使用 Event 未使用的函数和对象。 ,在您的情况下,包括那些不被 Event 识别的自己的对象父类(super class)型。

至已编辑的问题:

替代原则要求一个子类型(在概念上)将与其父类(super class)型在预期父类(super class)型的任何地方的行为方式相同。
因此,您的问题归结为“如果函数签名需要 Event,这不是它所期望的吗?”

答案可能会让您感到惊讶,但它是 - “不,它没有”。

原因是函数的隐式接口(interface)(或隐式合约,如果您愿意)。正如您正确指出的那样,有些语言具有非常强大和复杂的类型规则,可以更好地定义显式接口(interface),从而缩小允许使用的实际类型。然而,单独的形式参数类型并不总是完整的预期契约。

在没有强(或任何)类型的语言中,函数的签名没有或很少说明预期的参数类型。然而,他们仍然希望这些论点仅限于一些隐含的契约。例如,这是 python 函数所做的,C++ 模板函数所做的,以及得到 void* 的函数。在 C 中做。他们没有表达这些要求的句法机制这一事实并没有改变他们期望参数遵守已知契约(Contract)的事实。

即使像 Java 或 C# 这样的强类型语言也不能总是使用其声明的类型来定义参数的所有要求。因此,例如,您可以调用 multiply(a, b)divide(a, b)使用相同的类型——整数、 double 数等等;然而,devide()期待不同的契约(Contract):b不能为0!

当您查看 Event现在的机制,你可以理解不是每个Listener旨在处理任何 Event .一般使用EventListener争论是由于语言限制(所以在 Java 中你可以更好地定义正式契约(Contract),在 Python 中 - 根本没有,而在 JS 中 - 介于两者之间)。你应该问自己的是:

代码中是否存在 Event 类型的对象? (不是 Event 的某些其他特定子类型,而是 Event 本身)可能会被使用,但是 KeyboardEvent也许不会?另一方面 - 代码中是否存在 Listener可能会使用对象(而不是它的某些特定子类型),但可能不会使用特定的监听器?如果两者的答案都是否定的——我们很好。

关于javascript - JavaScript 事件系统是否违反了 LSP?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43244192/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com