JavaScript事件系統是否違反了LSP?
.
通過致電API/EventTarget" rel="nofollow,noindex" target="_blank">
EventTarget.dispatchEvent
,我們可能會派出一個任意型別的
Event
,可能會被註冊的
EventListener
處理.
interface EventListener { void handleEvent(in Event evt); }
如果我正確地理解LSP,那意味著anyEventListener.handleEvent(anyEvent)不應該失敗.然而,通常情況並非如此,因為事件偵聽器將經常使用專門的事件子型別的屬性.
在不支援泛型的型別語言中,該設計基本上需要將Event物件縮減為EventListener中的預期子型別.
從我的理解來看,上述設計可以被認為是違反LSP的.我是正確的還是通過
EventTarget.addEventListener
註冊偵聽器時必須提供型別的簡單事實可以防止LSP違規?
編輯:
雖然每個人似乎都專注於事件子類沒有違反LSP,但實際上我擔心的事實是,EventListener實現者將通過限制EventListener介面的前提條件來違反LSP. void handleEvent(在事件evt)中的任何事情都沒有告訴你通過傳遞錯誤的事件子型別可能會中斷某些事情.
在具有泛型的強型別語言中,介面可以表示為EventListener<T extends Event>使得實施者可以明確地使合同明確. SomeHandler實現了EventListener<SomeEvent>.
在JS中,顯然沒有實際的介面,但是事件處理程式仍然需要符合規範,並且該規範中沒有任何允許處理程式來判斷它是否可以處理特定型別的事件.
這不是一個真正的問題,因為預期不會自己呼叫監聽器,而是被註冊並與特定型別相關聯的EventTarget呼叫.
我只是根據理論是否違反LSP感興趣.我想知道如果要避免這種違規行為(如果這樣被認為是合理的話),那麼合同就需要像以下那樣(儘管實用主義可能做得更好)
interface EventListener { bool handleEvent(in Event evt); //returns wheter or not the event could be handled }
LSP的含義非常簡單:Subtype不能以違反其超型別行為的方式進行操作.那個“超型別”行為是基於設計定義的,但一般來說,它只是意味著可以繼續使用該物件,就像它是專案中任何位置的超型別一樣.
所以,在你的情況下,它應該遵循以下幾點:
(1)KeyboardEvent可以用於預期事件程式碼的任何地方;
(2)對於Event中的任何函式Event.func(),相應的KeyboardEvent.func()接受Event.func()的引數或其超型別的型別,返回Event.Func()或其子型別的型別,並丟擲Event.func()throws或其子型別;
(3)通過對Event.func()(歷史規則)不能發生的方式,KeyboardEvent.func()的呼叫不會改變KeyboardEvent的事件部分(資料成員).
什麼是LSP不需要的,對於func()的KeyboardEvent實現有任何限制,只要它在概念上是什麼Event.func()應該的.因此,它可以使用Event不被使用的函式和物件,包括在您的情況下,其自身物件的事件不被事件超型別識別.
編輯問題:
替代原則要求子型別(概念上)與其超型別在超型別預期的任何地方相同.
因此,您的問題歸結為“如果功能簽名需要事件,這不是預期的嗎?”
這個答案可能會讓你感到驚訝,但它是 – “不,不是”.
其原因是該函式的隱式介面(或隱式契約,如果您願意).正如你正確地指出的那樣,有一些語言具有非常強大和複雜的打字規則,允許更好地定義顯式介面,從而縮小允許使用的實際型別.然而,正式的論證型別並不總是預期的合約.
在沒有強(或任何)打字的語言中,函式的簽名對於期望的引數型別沒有任何意義或一點點.然而,他們仍然希望將論點限於一些隱含的合同.例如,這是python函式做什麼,C模板函式做什麼,C做什麼函式得到void *.事實上,他們沒有句法機制來表達這些要求,並沒有改變他們期望引數服從已知合同的事實.
即使非常強的型別的語言,如Java或C#,也不能總是使用其宣告的型別定義引數的所有要求.因此,例如,您可以使用相同的型別呼叫乘法(a,b)和除(a,b) – 整數,雙精度,無論如何;但是,devide()期望一個不同的合同:b不能為0!
當您現在看事件機制時,您可以理解,並不是每個監聽器都被設計為處理任何事件.使用一般的事件和偵聽器引數是由於語言限制(所以在Java中,你可以更好地定義正式的合同,在Python中,而不是在JS中).你應該問的是:
程式碼中有沒有一個地方可以使用事件型別的物件(不是事件的其他特定子型別,但是事件本身),但是KeyboardEvent可能不是?另一方面 – 程式碼中是否有一個可以使用Listener物件(而不是某個特定子型別)的地方,但該特定的監聽器可能不是?如果兩者的答案是否定的 – 我們很好.
http://stackoverflow.com/questions/43244192/does-the-javascript-event-system-violates-the-lsp