ฉันเข้าใจอย่างถูกต้องหรือไม่ว่าหลักการแทน Liskovไม่สามารถสังเกตได้ในภาษาที่วัตถุสามารถตรวจสอบตัวเองเช่นภาษาเป็ดที่พิมพ์เป็นปกติ
ยกตัวอย่างเช่นในทับทิมถ้าระดับB
สืบทอดจากชั้นเรียนA
แล้วสำหรับวัตถุทุกx
ของA
, x.class
เป็นไปได้กลับมาA
แต่ถ้าx
เป็นวัตถุของB
, จะไม่กลับมาx.class
A
นี่คือคำแถลงของ LSP:
Let Q (x)เป็นสถานที่ให้บริการสามารถพิสูจน์ได้เกี่ยวกับวัตถุxประเภทT จากนั้นQ (y)ควรจะสามารถพิสูจน์ได้สำหรับวัตถุYประเภทSที่Sเป็นชนิดย่อยของT
ดังนั้นใน Ruby เช่น
class T; end
class S < T; end
ละเมิด LSP ในแบบฟอร์มนี้ตามที่เห็นในคุณสมบัติq (x) =x.class.name == 'T'
ส่วนที่เพิ่มเข้าไป. หากคำตอบคือ "ใช่" (LSP ไม่เข้ากับการวิปัสสนา) คำถามอื่น ๆ ของฉันจะเป็น: มีรูปแบบที่อ่อนแอของ LSP ที่ "อ่อนแอ" ซึ่งอาจจะเก็บไว้เป็นภาษาไดนามิกอาจอยู่ภายใต้เงื่อนไขเพิ่มเติมบางอย่างและมีชนิดพิเศษเท่านั้น ของคุณสมบัติ
ปรับปรุง สำหรับการอ้างอิงนี่เป็นอีกสูตรของ LSP ที่ฉันพบบนเว็บ:
ฟังก์ชันที่ใช้พอยน์เตอร์หรือการอ้างอิงไปยังคลาสพื้นฐานต้องสามารถใช้วัตถุของคลาสที่ได้รับโดยไม่ต้องรู้
เเละอีกอย่าง:
หาก S เป็นประเภทย่อยที่ประกาศไว้ของ T วัตถุประเภท S ควรทำงานเป็นวัตถุประเภท T ที่คาดว่าจะทำงานหากพวกเขาถือว่าเป็นวัตถุประเภท T
คนสุดท้ายมีคำอธิบายประกอบด้วย:
โปรดทราบว่า LSP นั้นเกี่ยวกับพฤติกรรมที่คาดหวังของวัตถุ หนึ่งสามารถติดตาม LSP หากมีความชัดเจนเกี่ยวกับพฤติกรรมที่คาดหวังของวัตถุ
สิ่งนี้ดูเหมือนจะอ่อนแอกว่าเดิมและอาจเป็นไปได้ที่จะสังเกต แต่ฉันอยากเห็นมันเป็นระเบียบโดยเฉพาะอธิบายว่าใครตัดสินใจว่าพฤติกรรมที่คาดหวังคืออะไร
จากนั้น LSP ไม่ใช่คุณสมบัติของคู่ของคลาสในภาษาการเขียนโปรแกรม แต่เป็นคู่ของคลาสพร้อมกับชุดของคุณสมบัติที่กำหนดซึ่งเป็นที่พอใจของคลาสบรรพบุรุษหรือไม่ ในทางปฏิบัตินี่จะหมายถึงการสร้าง subclass (ระดับลูกหลาน) ที่เกี่ยวกับ LSP การใช้คลาสที่เป็นไปได้ทั้งหมดต้องเป็นที่รู้จักหรือไม่? จากข้อมูลของ LSP คลาสของบรรพบุรุษนั้นควรจะถูกแทนที่ด้วยคลาสของการสืบทอดใด ๆ ใช่ไหม?
ปรับปรุง ฉันยอมรับคำตอบแล้ว แต่ฉันต้องการเพิ่มอีกตัวอย่างที่เป็นรูปธรรมจาก Ruby เพื่อแสดงคำถาม ใน Ruby แต่ละคลาสเป็นโมดูลในแง่ที่ว่าClass
class เป็นผู้สืบทอดของModule
คลาส อย่างไรก็ตาม:
class C; end
C.is_a?(Module) # => true
C.class # => Class
Class.superclass # => Module
module M; end
M.class # => Module
o = Object.new
o.extend(M) # ok
o.extend(C) # => TypeError: wrong argument type Class (expected Module)