หลักการชดเชย Liskov เข้ากันไม่ได้กับการวิปัสสนาหรือการพิมพ์ดีดเป็ด?


11

ฉันเข้าใจอย่างถูกต้องหรือไม่ว่าหลักการแทน Liskovไม่สามารถสังเกตได้ในภาษาที่วัตถุสามารถตรวจสอบตัวเองเช่นภาษาเป็ดที่พิมพ์เป็นปกติ

ยกตัวอย่างเช่นในทับทิมถ้าระดับBสืบทอดจากชั้นเรียนAแล้วสำหรับวัตถุทุกxของA, x.classเป็นไปได้กลับมาAแต่ถ้าxเป็นวัตถุของB, จะไม่กลับมาx.classA

นี่คือคำแถลงของ 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 แต่ละคลาสเป็นโมดูลในแง่ที่ว่าClassclass เป็นผู้สืบทอดของ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)

2
เกือบทุกภาษาในปัจจุบันให้ระดับของการวิปัสสนาดังนั้นคำถามที่ไม่เฉพาะเจาะจงกับทับทิม
Joachim Sauer

ฉันเข้าใจฉันให้ทับทิมเป็นตัวอย่าง ฉันไม่รู้ว่าบางทีในภาษาอื่นที่มีวิปัสสนามี "รูปแบบอ่อนแอ" ของ LSP แต่ถ้าฉันเข้าใจหลักการอย่างถูกต้องมันไม่เข้ากันกับวิปัสสนา
Alexey

ฉันได้ลบ "Ruby" ออกจากชื่อแล้ว
Alexey

2
คำตอบสั้น ๆ คือเข้ากันได้ นี่คือโพสต์บล็อกที่ฉันเห็นด้วยเป็นส่วนใหญ่: หลักการทดแทน Liskov สำหรับการพิมพ์ดีดเป็ด
K.Steff

2
@Alexey Properties ในบริบทนี้เป็นค่าคงที่ของวัตถุ ตัวอย่างเช่นวัตถุที่ไม่เปลี่ยนรูปมีคุณสมบัติที่ค่าของพวกเขาจะไม่เปลี่ยนแปลง หากคุณดูการทดสอบหน่วยที่ดีพวกเขาควรทดสอบคุณสมบัติเหล่านี้อย่างแน่นอน
K.Steff

คำตอบ:


29

นี่คือหลักการที่แท้จริง :

อนุญาตq(x)เป็นพิสูจน์คุณสมบัติเกี่ยวกับวัตถุชนิดx Tจากนั้นq(y)ควรจะสามารถพิสูจน์ได้สำหรับวัตถุyชนิดSที่เป็นชนิดย่อยของST

และสรุปวิกิพีเดียที่ยอดเยี่ยม:

มันระบุว่าในโปรแกรมคอมพิวเตอร์ถ้า S เป็นประเภทย่อยของ T แล้ววัตถุประเภท T อาจถูกแทนที่ด้วยวัตถุประเภท S (เช่นวัตถุประเภท S อาจถูกแทนที่สำหรับวัตถุประเภท T) โดยไม่มีการเปลี่ยนแปลงใด ๆ ของ คุณสมบัติที่ต้องการของโปรแกรมนั้น (ความถูกต้อง, งานที่ต้องทำ ฯลฯ )

และคำพูดที่เกี่ยวข้องจากกระดาษ:

สิ่งที่ต้องการคือความต้องการที่แข็งแกร่งกว่าซึ่ง จำกัด พฤติกรรมของประเภทย่อย: คุณสมบัติที่สามารถพิสูจน์ได้โดยใช้สเปคของประเภทที่สันนิษฐานของวัตถุควรเก็บไว้แม้ว่าวัตถุนั้นจะเป็นสมาชิกประเภทย่อยของ ...

ข้อมูลจำเพาะประเภทรวมถึงข้อมูลต่อไปนี้:
- ชื่อของประเภท;
- คำอธิบายของพื้นที่ค่าประเภท;
- สำหรับวิธีการแต่ละประเภท:
--- ชื่อ;
--- ลายเซ็นของมัน (รวมถึงข้อยกเว้นสัญญาณ);
--- พฤติกรรมในแง่ของเงื่อนไขก่อนและหลังเงื่อนไข

ดังนั้นคำถาม:

ฉันเข้าใจอย่างถูกต้องหรือไม่ว่าหลักการแทน Liskov ไม่สามารถสังเกตได้ในภาษาที่วัตถุสามารถตรวจสอบตัวเองเช่นภาษาเป็ดที่พิมพ์เป็นปกติ

เลขที่

A.classส่งคืนคลาส
B.classส่งคืนคลาส

เนื่องจากคุณสามารถโทรในประเภทที่เฉพาะเจาะจงมากขึ้นและรับผลลัพธ์ที่เข้ากันได้ LSP จึงจัดเก็บไว้ ปัญหาคือว่าด้วยภาษาแบบไดนามิกคุณยังสามารถเรียกสิ่งต่าง ๆ บนผลลัพธ์ที่คาดหวังว่าพวกเขาจะมี

แต่ลองพิจารณาภาษาที่พิมพ์ด้วยโครงสร้าง (เป็ด) แบบสแตติก ในกรณีนี้A.classจะส่งคืนประเภทที่มีข้อ จำกัด ว่าจะต้องAเป็นประเภทย่อยAหรือ สิ่งนี้ให้การรับประกันแบบคงที่ว่าประเภทย่อยใด ๆ ของAต้องจัดให้มีวิธีการT.classที่ผลลัพธ์เป็นประเภทที่เป็นไปตามข้อ จำกัด นั้น

นี่เป็นการยืนยันที่แข็งแกร่งว่า LSP มีภาษาที่รองรับการพิมพ์เป็ดและการละเมิด LSP ในรูปแบบใด ๆ เช่น Ruby เกิดขึ้นมากขึ้นเนื่องจากการใช้งานผิดปกติแบบไดนามิกมากกว่าความไม่ลงรอยกันของการออกแบบภาษา


1
"เนื่องจากคุณสามารถโทรแบบเดียวกันกับประเภทที่เฉพาะเจาะจงมากขึ้นและรับผลลัพธ์ที่เข้ากันได้ LSP จึงถือ" LSP เก็บหากผลลัพธ์เหมือนกันถ้าฉันเข้าใจถูกต้อง อาจมีบางรูปแบบของ "สัปดาห์" ของ LSP ที่เกี่ยวข้องกับข้อ จำกัด ที่กำหนดต้องใช้แทนคุณสมบัติทั้งหมดที่มีข้อ จำกัด ที่กำหนดเท่านั้นที่จะพึงพอใจ ในกรณีใด ๆ ฉันจะขอบคุณอ้างอิงใด ๆ
Alexey

@Alexey แก้ไขเพื่อรวมความหมายของ LSP ถ้าฉันสามารถใช้ B ในจุดที่ฉันคาดหวังได้ A ก็จะถือ LSP ฉันอยากรู้ว่าคุณคิดอย่างไรกับ. class ของ Ruby อาจละเมิดสิ่งนั้น
Telastyn

3
@Alexey - หากโปรแกรมของคุณมีfail unless x.foo == 42และชนิดย่อยส่งคืน 0 นั่นคือสิ่งเดียวกัน นี่ไม่ใช่ความล้มเหลวของ LSP มันเป็นการทำงานปกติของโปรแกรมของคุณ ความแตกต่างไม่ได้เป็นการละเมิด LSP
Telastyn

1
@ Alexey - แน่นอน สมมติว่ามันเป็นคุณสมบัติ ในกรณีนั้นรหัสของคุณละเมิด LSP เนื่องจากไม่อนุญาตให้มีชนิดย่อยที่มีความหมายเหมือนกัน แต่มันไม่ได้พิเศษเป็นพิเศษกับภาษาแบบไดนามิกหรือเป็ดพิมพ์ ไม่มีอะไรที่พวกเขาทำในการออกแบบภาษาที่ทำให้เกิดการละเมิด รหัสที่คุณเขียนทำ โปรดจำไว้ว่า LSP เป็นหลักการของการออกแบบโปรแกรม (ดังนั้นควรในคำจำกัดความ) มากกว่าคุณสมบัติทางคณิตศาสตร์ของโปรแกรม
Telastyn

6
@Alexey: หากคุณเขียนสิ่งที่ขึ้นอยู่กับ x.class == A มันเป็นรหัสของคุณที่ละเมิด LSPไม่ใช่ภาษา เป็นไปได้ที่จะเขียนโค้ดที่ละเมิด LSP ในเกือบทุกภาษาโปรแกรม
Andres F.

7

ในบริบทของ LSP "คุณสมบัติ" เป็นสิ่งที่สามารถสังเกตเห็นได้ในประเภท (หรือวัตถุ) โดยเฉพาะมันพูดถึง "ทรัพย์สินที่พิสูจน์ได้"

"คุณสมบัติ" ดังกล่าวอาจมีfoo()วิธีการที่ไม่มีค่าตอบแทน (และเป็นไปตามสัญญาที่กำหนดไว้ในเอกสารประกอบ)

ตรวจสอบให้แน่ใจว่าคุณไม่ได้สับสนคำนี้ด้วย "คุณสมบัติ" ในขณะที่ " classเป็นคุณสมบัติของทุกวัตถุในทับทิม" "คุณสมบัติ" ดังกล่าวอาจเป็น "คุณสมบัติ LSP" แต่มันไม่เหมือนกันโดยอัตโนมัติ!

ตอนนี้คำตอบสำหรับคำถามของคุณขึ้นอยู่กับความเข้มงวดของคุณในการกำหนด "คุณสมบัติ" ถ้าคุณพูดว่า "คุณสมบัติของคลาสAนั้น.classจะคืนค่าชนิดของวัตถุ" ดังนั้นBจริงๆแล้วจะมีคุณสมบัตินั้น

แต่ถ้าคุณกำหนด "ทรัพย์สิน" ให้เป็น " .classผลตอบแทนA" แล้วเห็นได้ชัดBไม่ได้มีทรัพย์สินที่

อย่างไรก็ตามคำจำกัดความที่สองนั้นไม่มีประโยชน์มากนักเนื่องจากคุณได้พบวิธีการปัดเศษเป็นรอบเพื่อประกาศค่าคงที่


ฉันสามารถคิดถึงคำจำกัดความเดียวของ "คุณสมบัติ" ของโปรแกรม: สำหรับอินพุตที่กำหนดมันส่งคืนค่าที่กำหนดหรือโดยทั่วไปเมื่อใช้เป็นบล็อกในโปรแกรมอื่นโปรแกรมอื่นสำหรับอินพุตที่กำหนดจะส่งกลับค่า ค่าที่กำหนด ด้วยคำจำกัดความนี้ฉันไม่เห็นความหมายว่า " .classจะคืนค่าชนิดของวัตถุ" ถ้ามันหมายความว่าx.class == x.classนี่ไม่ใช่ทรัพย์สินที่น่าสนใจ
Alexey

1
@Alexey: ฉันได้อัปเดตคำถามของฉันพร้อมคำชี้แจงเกี่ยวกับความหมายของ "คุณสมบัติ" ในบริบทของ LSP
Joachim Sauer

2
@Alexey: มองเข้าไปในกระดาษฉันไม่พบคำจำกัดความที่เจาะจงหรือ "คุณสมบัติ" อาจเป็นเพราะคำนี้ใช้ในความหมายทั่วไปของ CS "สิ่งที่สามารถสังเกต / พิสูจน์ได้เกี่ยวกับวัตถุบางอย่าง" มันมีอะไรจะทำอย่างไรกับ meaing อื่น ๆ "สนามของวัตถุ"
Joachim Sauer

4
@Alexey: ฉันไม่รู้ว่าฉันจะบอกอะไรคุณได้อีก ฉันใช้คำจำกัดความของ "คุณสมบัติคือคุณภาพหรือความสนใจของวัตถุ" "สี" เป็นคุณสมบัติของวัตถุที่มีอยู่จริงและมองเห็นได้ "ความหนาแน่น" เป็นคุณสมบัติของวัสดุ "การมีวิธีการที่ระบุ" เป็นคุณสมบัติของคลาส / วัตถุ
Joachim Sauer

4
@Alexey: ฉันคิดว่าคุณกำลังโยนลูกอาบน้ำอาบน้ำ: เพียงเพราะคุณสมบัติบางอย่าง LSP ที่ไม่สามารถทำให้ค้างไว้ได้ไม่ได้หมายความว่ามันไร้ประโยชน์หรือ "ไม่มีภาษาใด ๆ " แต่การสนทนานั้นจะไปไกลถึงที่นี่
Joachim Sauer

5

ตามที่ฉันเข้าใจแล้วไม่มีอะไรเกี่ยวกับวิปัสสนาที่จะขัดกับ LSP โดยพื้นฐานตราบเท่าที่วัตถุรองรับวิธีการเดียวกันกับอีกวิธีหนึ่งวัตถุทั้งสองควรเปลี่ยนได้ นั่นคือถ้ารหัสของคุณคาดว่าAddressวัตถุนั้นมันไม่สำคัญว่าจะเป็นCustomerAddressหรือWarehouseAddressตราบใดที่ทั้งสองให้ (เช่น) getStreetAddress(), getCityName(), และgetRegion() getPostalCode()แน่นอนคุณสามารถสร้างมัณฑนากรบางประเภทที่ใช้วัตถุประเภทอื่นและใช้วิปัสสนาเพื่อให้วิธีการที่ต้องการ (เช่นDestinationAddressคลาสที่ใช้Shipmentวัตถุและนำเสนอที่อยู่ผู้รับสินค้าเป็นAddress) แต่มันไม่จำเป็นและไม่ต้องการแน่นอน ไม่ป้องกัน LSP จากการใช้งาน


2
@Alexey: วัตถุต่าง ๆ นั้น "เหมือนกัน" ถ้ามันรองรับวิธีการเดียวกัน ซึ่งหมายถึงชื่อเดียวกันหมายเลขและชนิดของอาร์กิวเมนต์ที่เหมือนกันชนิดส่งคืนที่เหมือนกันและผลข้างเคียงที่เหมือนกัน (ตราบใดที่รหัสเหล่านี้สามารถมองเห็นได้) วิธีการอาจทำงานแตกต่างไปจากเดิมอย่างสิ้นเชิง แต่ตราบใดที่พวกเขาปฏิบัติตามสัญญา
TMN

1
@ Alexey: แต่ทำไมฉันถึงมีสัญญาแบบนี้? สิ่งที่ใช้งานจริงสัญญาที่ไม่ตอบสนอง? ถ้าผมมีสัญญาเช่นฉันก็สามารถใช้ทดแทน occurance ของทุกx.class.nameที่มี'A' ผลทำให้ไร้ประโยชน์x.class.name
Joachim Sauer

1
@Alexey: อีกครั้ง: เพียงเพราะคุณสามารถกำหนดสัญญาที่ไม่สามารถเติมเต็มได้โดยการขยายคลาสอื่นไม่ทำให้ LSP เสียหาย นั่นหมายถึงคุณได้สร้างคลาสที่ไม่สามารถขยายได้ หากฉันกำหนดวิธีการที่จะ "ส่งคืนถ้าการบล็อกโค้ดที่ให้ไว้สิ้นสุดในเวลา จำกัด " จากนั้นฉันก็มีสัญญาที่ไม่สามารถปฏิบัติตามได้ ไม่ได้หมายความว่าการเขียนโปรแกรมไม่มีประโยชน์
Joachim Sauer

2
@Alexey พยายามที่จะตรวจสอบว่าx.class.name == 'A'เป็นรูปแบบการต่อต้านในการพิมพ์เป็ด: หลังจากทั้งหมดการพิมพ์เป็ดมาจาก "ถ้ามัน quacks และเดินเหมือนเป็ดมันเป็นเป็ด" ดังนั้นหากมันทำตัวเหมือนAและให้เกียรติสัญญาที่Aวางไว้มันเป็นAตัวอย่าง
K.Steff

1
@Alexey คุณได้รับการนำเสนอด้วยคำจำกัดความที่ชัดเจน คลาสของวัตถุไม่ได้เป็นส่วนหนึ่งของพฤติกรรมหรือสัญญาหรือสิ่งที่คุณต้องการเรียกใช้ คุณกำลังกำกวม "คุณสมบัติ" กับ "เขตข้อมูลวัตถุเช่น x.myField" ซึ่งได้รับการชี้ให้เห็นมันไม่เหมือนกัน ในบริบทนี้คุณสมบัติจะเหมือนคุณสมบัติทางคณิตศาสตร์มากกว่าเช่นประเภทค่าคงที่ นอกจากนี้ยังเป็นรูปแบบการต่อต้านเพื่อตรวจสอบประเภทที่แน่นอนหากคุณต้องการพิมพ์เป็ด แล้วคุณมีปัญหาอะไรกับ LSP และการพิมพ์เป็ดอีกครั้ง ;)
Andres F.

4

หลังจากอ่านบทความต้นฉบับของบาร์บาร่าลิสคอฟฉันได้ค้นพบวิธีทำให้คำจำกัดความของวิกิพีเดียเสร็จสมบูรณ์เพื่อให้ LSP พึงพอใจในเกือบทุกภาษา

ก่อนอื่นคำว่า"พิสูจน์ได้"มีความสำคัญในคำจำกัดความ ไม่ได้อธิบายไว้ในบทความ Wikipedia และมีการกล่าวถึง "ข้อ จำกัด " ที่อื่นโดยไม่มีการอ้างอิง

นี่คือคำพูดที่สำคัญครั้งแรกจากกระดาษ:

สิ่งที่ต้องการคือความต้องการที่แข็งแกร่งกว่าซึ่ง จำกัด พฤติกรรมของประเภทย่อย: คุณสมบัติที่สามารถพิสูจน์ได้ โดยใช้สเปค ของประเภทที่สันนิษฐานของวัตถุควรเก็บไว้แม้ว่าวัตถุนั้นจะเป็นสมาชิกประเภทย่อย ...

และนี่คือข้อที่สองอธิบายว่าสเปคประเภทคืออะไร:

ข้อมูลจำเพาะชนิดรวมถึงข้อมูลต่อไปนี้:

  • ชื่อประเภท
  • คำอธิบายของพื้นที่ค่าของประเภท;
  • สำหรับวิธีการแต่ละประเภท:
    • ชื่อของมัน;
    • ลายเซ็นของมัน (รวมถึงข้อยกเว้นสัญญาณ);
    • พฤติกรรมในแง่ของเงื่อนไขก่อนและหลังเงื่อนไข

ดังนั้น LSP จึงเหมาะสมกับข้อกำหนดของประเภทที่กำหนดเท่านั้นและสำหรับข้อกำหนดประเภทที่เหมาะสม (สำหรับตัวอย่างที่ว่างเปล่า) ก็สามารถทำได้ในภาษาใดก็ได้

ฉันคิดว่าคำตอบของ Telastynนั้นใกล้เคียงกับสิ่งที่ฉันค้นหามากที่สุดเพราะ "ข้อ จำกัด " ถูกกล่าวถึงอย่างชัดเจน


Telastyn หากคุณสามารถเพิ่มราคาเหล่านี้ให้กับคำตอบของคุณฉันต้องการยอมรับราคาของคุณมากกว่าของฉันเอง
Alexey

2
มาร์กอัปนั้นไม่เหมือนกันและฉันเปลี่ยนการเน้นเล็กน้อย แต่มีการรวมราคาไว้ด้วย
Telastyn

ขออภัยโจอาคิมซาวเออร์กล่าวถึงคุณสมบัติ "พิสูจน์ได้" ซึ่งคุณไม่ชอบ โดยทั่วไปแล้วคุณเพิ่งปรับปรุงคำตอบที่มีอยู่เดิม สุจริตฉันไม่รู้ว่าคุณกำลังมองหา ...
Andres F.

ไม่ไม่มีการอธิบายว่า "พิสูจน์ได้จากอะไร" คุณสมบัติx.class.name = 'A'นี้สามารถพิสูจน์ได้สำหรับทุกxชั้นAถ้าคุณอนุญาตความรู้มากเกินไป ข้อกำหนดประเภทไม่ได้กำหนดและความสัมพันธ์ที่แน่นอนกับ LSP ไม่ได้เป็นอย่างใดอย่างหนึ่ง แต่ไม่เป็นทางการบ่งชี้บางอย่างที่ได้รับ ฉันได้พบสิ่งที่ฉันกำลังมองหาในกระดาษของ Liskov และตอบคำถามของฉันด้านบน
Alexey

ฉันคิดว่าคำที่คุณกล้าเป็นกุญแจสำคัญ หากเอกสารประเภทซุปเปอร์ที่สำหรับประเภทใดxประเภทหนึ่งx.woozleจะให้ผลตอบแทนundefinedดังนั้นประเภทที่x.woozleไม่ได้รับผลตอบแทนundefinedจะเป็นประเภทย่อยที่เหมาะสม หาก supertype ไม่ได้บันทึกอะไรเลยx.woozleความจริงที่ว่าการใช้x.woozlesupertype นั้นจะเกิดขึ้นกับผลตอบแทนundefinedก็ไม่ได้หมายความว่าจะเกิดอะไรขึ้นกับสิ่งที่อยู่ใน subtype
supercat

3

ในการอ้างอิงบทความของ Wikipedia เกี่ยวกับ LSP "การแทนที่เป็นหลักการในการเขียนโปรแกรมเชิงวัตถุ" มันเป็นหลักการและเป็นส่วนหนึ่งของการออกแบบโปรแกรมของคุณ หากคุณเขียนรหัสที่ขึ้นอยู่กับx.class == Aว่ามันเป็นรหัสของคุณที่ละเมิด LSP โปรดทราบว่ารหัสที่ใช้ไม่ได้ประเภทนี้สามารถใช้กับ Java ได้โดยไม่จำเป็นต้องพิมพ์เป็ด

ไม่มีอะไรในการพิมพ์เป็ดแบ่ง LSP โดยเนื้อแท้ เฉพาะในกรณีที่คุณใช้ในทางที่ผิดเช่นในตัวอย่างของคุณ

ความคิดเพิ่มเติม: ไม่ได้ตรวจสอบอย่างชัดเจนว่าคลาสของวัตถุนั้นเอาชนะเป้าหมายของการพิมพ์เป็ดได้หรือไม่


คุณสามารถให้คำจำกัดความของ LSP ได้ไหม
Alexey

1
@Alexey คำจำกัดความที่แม่นยำของ LSP ระบุไว้ใน Wikipedia ในแง่ของชนิดย่อย Liskov's notion of a behavioral subtype defines a notion of substitutability for mutable objects; that is, if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program (e.g., correctness).คำนิยามที่ไม่เป็นทางการ คลาสที่แน่นอนของวัตถุไม่ใช่หนึ่งใน "คุณสมบัติที่ต้องการของโปรแกรม"; มิฉะนั้นมันจะทำงานตรงกันข้ามกับการพิมพ์เป็ดไม่เพียง แต่พิมพ์ย่อยทั่วไปรสของ Java รวม
Andres F.

2
@Alexey โปรดทราบว่าตัวอย่างของคุณx.class == Aละเมิด LSP และการพิมพ์เป็ด ไม่มีเหตุผลในการใช้การพิมพ์เป็ดหากคุณกำลังจะตรวจสอบประเภทจริง
Andres F.

Andres ความหมายนี้ไม่แม่นยำพอที่ฉันจะเข้าใจ รายการใดรายการหนึ่งหรือรายการใด คุณสมบัติที่พึงประสงค์คืออะไร? หากคลาสอยู่ในไลบรารีแอ็พพลิเคชันอื่นอาจพิจารณาคุณสมบัติที่ต้องการต่างกัน ไม่เห็นว่าบรรทัดของรหัสสามารถละเมิด LSP เพราะฉันคิดว่า LSP เป็นทรัพย์สินของคู่ของชั้นเรียนในภาษาการเขียนโปรแกรมที่กำหนด: อย่างใดอย่างหนึ่ง ( A, B) ตอบสนอง LSP หรือไม่ หาก LSP ขึ้นอยู่กับรหัสที่ใช้ในที่อื่น ๆ จะไม่มีการอธิบายว่าต้องใช้รหัสใด ฉันหวังว่าจะพบบางสิ่งที่นี่: cse.ohio-state.edu/~neelam/courses/788/lwb.pdf
Alexey

2
@Alexey LSP ถือ (หรือไม่) สำหรับการออกแบบที่เฉพาะเจาะจง เป็นสิ่งที่มองหาในการออกแบบ มันไม่ใช่คุณสมบัติของภาษาโดยทั่วไป Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of Tมันไม่ได้มีความแม่นยำมากขึ้นกว่าความหมายที่แท้จริง: เห็นได้ชัดว่าx.classไม่ใช่คุณสมบัติที่น่าสนใจที่นี่ มิฉะนั้นความหลากหลายของ Javaจะไม่ทำงานเช่นกัน มีอะไรที่ธรรมชาติเพื่อเป็ดพิมพ์ใน "ปัญหา x.class ของคุณ" คุณเห็นด้วยไหม
Andres F.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.