โดยพื้นฐานแล้วเราต้องการให้สิ่งต่าง ๆ ประพฤติอย่างสมเหตุสมผล
พิจารณาปัญหาต่อไปนี้:
ฉันได้รับสี่เหลี่ยมกลุ่มหนึ่งและฉันต้องการเพิ่มพื้นที่ของพวกเขา 10% สิ่งที่ฉันทำคือฉันตั้งความยาวของสี่เหลี่ยมผืนผ้าเป็น 1.1 เท่าของที่เคยเป็นมาก่อน
public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles)
{
foreach(var rectangle in rectangles)
{
rectangle.Length = rectangle.Length * 1.1;
}
}
ในกรณีนี้สี่เหลี่ยมทุกอันของฉันมีความยาวเพิ่มขึ้น 10% ซึ่งจะเพิ่มพื้นที่ของพวกเขา 10% น่าเสียดายที่บางคนผ่านฉันไปเป็นสี่เหลี่ยมและสี่เหลี่ยมจริง ๆ และเมื่อความยาวของสี่เหลี่ยมถูกเปลี่ยนไปความกว้างก็คือ
การทดสอบหน่วยของฉันผ่านเพราะฉันเขียนการทดสอบหน่วยของฉันทั้งหมดเพื่อใช้คอลเลกชันของสี่เหลี่ยม ตอนนี้ฉันได้แนะนำข้อบกพร่องเล็กน้อยในแอปพลิเคชันของฉันซึ่งสามารถสังเกตได้หลายเดือน
ยิ่งกว่านั้น Jim จากบัญชีเห็นวิธีการของฉันและเขียนรหัสอื่นซึ่งใช้ความจริงที่ว่าถ้าเขาส่งกำลังสองเป็นวิธีการของฉันที่เขาได้รับการเพิ่มขนาด 21% ที่ดีมาก จิมมีความสุขและไม่มีใครฉลาด
จิมได้รับการเลื่อนตำแหน่งสำหรับการทำงานที่ยอดเยี่ยมในแผนกอื่น อัลเฟรดเข้าร่วม บริษัท ในฐานะผู้อยู่ใต้บังคับบัญชา ในรายงานบั๊กแรกของเขาจิลล์จากโฆษณาได้รายงานว่าการส่งกำลังสองไปยังวิธีนี้ส่งผลให้เพิ่มขึ้น 21% และต้องการแก้ไขบั๊ก อัลเฟรดเห็นว่ากำลังใช้ทุกหนทุกแห่งในรหัสและรูปสี่เหลี่ยมและตระหนักว่าการทำลายโซ่เป็นไปไม่ได้ เขายังไม่สามารถเข้าถึงซอร์สโค้ดของบัญชีได้ ดังนั้นอัลเฟรดแก้ไขข้อผิดพลาดเช่นนี้:
public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles)
{
foreach(var rectangle in rectangles)
{
if (typeof(rectangle) == Rectangle)
{
rectangle.Length = rectangle.Length * 1.1;
}
if (typeof(rectangle) == Square)
{
rectangle.Length = rectangle.Length * 1.04880884817;
}
}
}
อัลเฟรดมีความสุขกับทักษะการแฮ็ก uber ของเขาและจิลล์ลงนามว่าข้อผิดพลาดได้รับการแก้ไข
เดือนถัดไปไม่มีใครได้รับค่าจ้างเพราะการบัญชีนั้นขึ้นอยู่กับความสามารถในการส่งผ่านกำลังสองไปยังIncreaseRectangleSizeByTenPercent
วิธีการและเพิ่มพื้นที่ 21% ทั้ง บริษัท เข้าสู่โหมด "ลำดับความสำคัญ 1 แก้ไขข้อบกพร่อง" เพื่อติดตามแหล่งที่มาของปัญหา พวกเขาติดตามปัญหาเพื่อแก้ไขปัญหาของ Alfred พวกเขารู้ว่าพวกเขาต้องทำให้ทั้งบัญชีและการโฆษณามีความสุข ดังนั้นพวกเขาจึงแก้ไขปัญหาโดยการระบุผู้ใช้ด้วยวิธีการเรียกเช่น:
public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles)
{
IncreaseRectangleSizeByTenPercent(
rectangles,
new User() { Department = Department.Accounting });
}
public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles, User user)
{
foreach(var rectangle in rectangles)
{
if (typeof(rectangle) == Rectangle || user.Department == Department.Accounting)
{
rectangle.Length = rectangle.Length * 1.1;
}
else if (typeof(rectangle) == Square)
{
rectangle.Length = rectangle.Length * 1.04880884817;
}
}
}
และอื่น ๆ และอื่น ๆ.
เรื่องเล็ก ๆ น้อยนี้ขึ้นอยู่กับสถานการณ์ในโลกแห่งความเป็นจริงที่เผชิญกับโปรแกรมเมอร์ทุกวัน การละเมิดหลักการทดแทน Liskov สามารถแนะนำข้อผิดพลาดที่ละเอียดอ่อนมากซึ่งจะถูกหยิบขึ้นมาหลายปีหลังจากที่พวกเขาถูกเขียนซึ่งการแก้ไขการละเมิดจะทำลายหลายสิ่งและไม่แก้ไขมันจะทำให้ลูกค้ารายใหญ่ของคุณโกรธ
มีสองวิธีที่เป็นจริงในการแก้ไขปัญหานี้
วิธีแรกคือการทำให้รูปสี่เหลี่ยมผืนผ้าไม่เปลี่ยนรูป หากผู้ใช้ของ Rectangle ไม่สามารถเปลี่ยนคุณสมบัติความยาวและความกว้างปัญหานี้จะหายไป หากคุณต้องการสี่เหลี่ยมผืนผ้าที่มีความยาวและความกว้างแตกต่างกันให้คุณสร้างสี่เหลี่ยมผืนผ้าใหม่ สี่เหลี่ยมสามารถสืบทอดจากสี่เหลี่ยมได้อย่างมีความสุข
วิธีที่สองคือการทำลายห่วงโซ่มรดกระหว่างสี่เหลี่ยมและสี่เหลี่ยม หากสี่เหลี่ยมหมายถึงการมีSideLength
คุณสมบัติเดี่ยวและสี่เหลี่ยมมีLength
และWidth
คุณสมบัติและไม่มีการสืบทอดมันเป็นไปไม่ได้ที่จะทำลายสิ่งต่าง ๆ โดยไม่ได้ตั้งใจโดยคาดหวังว่ารูปสี่เหลี่ยมผืนผ้าและรับสี่เหลี่ยม ในคำศัพท์ C # คุณสามารถseal
เรียนรูปสี่เหลี่ยมผืนผ้าของคุณซึ่งทำให้แน่ใจว่ารูปสี่เหลี่ยมผืนผ้าทั้งหมดที่คุณได้รับนั้นเป็นรูปสี่เหลี่ยมจริง ๆ
ในกรณีนี้ฉันชอบวิธี "วัตถุที่ไม่เปลี่ยนรูป" ในการแก้ไขปัญหา ตัวตนของสี่เหลี่ยมคือความยาวและความกว้าง มันทำให้รู้สึกว่าเมื่อคุณต้องการเปลี่ยนเอกลักษณ์ของวัตถุสิ่งที่คุณต้องการคือวัตถุใหม่ ถ้าคุณสูญเสียลูกค้าเก่าและได้รับลูกค้าใหม่คุณไม่เปลี่ยนข้อมูลจากลูกค้าเก่าไปใหม่คุณสร้างใหม่Customer.Id
Customer
การละเมิดหลักการทดแทน Liskov เป็นเรื่องธรรมดาในโลกแห่งความเป็นจริงส่วนใหญ่เป็นเพราะมีการเขียนโค้ดจำนวนมากโดยคนที่ไร้ความสามารถ / ภายใต้แรงกดดันด้านเวลา / ไม่สนใจ / ทำผิดพลาด มันสามารถและนำไปสู่ปัญหาที่น่ารังเกียจบางอย่าง ในกรณีส่วนใหญ่คุณต้องการสนับสนุนการแต่งเพลงมากกว่าการสืบทอดแทน