Liskov Substitution Principle หรือที่เรามักจะย่อว่า LSP คือหลักการหนึ่งในหลักการออกแบบโค้ดของการเขียนโปรแกรมวัตถุที่สำคัญ (Object-Oriented Programming - OOP) ซึ่งถูกค้นคว้าและนำเสนอโดย บาร์บาร่า ลิสโคฟ (Barbara Liskov) ในปี 1987 หลักการนี้มีความสำคัญมากเพราะช่วยให้โปรแกรมของเรามีความยืดหยุ่นและสามารถขยายหรือปรับเปลี่ยนการทำงานได้ง่ายโดยไม่ทำให้เกิดปัญหาในส่วนอื่นๆ ของระบบ
คิดภาพนี้... คุณเห็นกล่องขนมต่างๆอยู่บนโต๊ะ กล่องทุกกล่องบอกว่า "ขนม" พอคุณเปิดดู, คุณคาดหวังว่าจะเจอขนม ไม่ว่าจะเป็นคุกกี้, ช็อคโกแลตหรืออะไรก็ตามที่เป็นขนม นั่นหมายความว่าไม่ว่าคุณจะเปลี่ยนกล่องในมือคุณจากกล่องหนึ่งไปยังอีกกล่องหนึ่งที่มีฉลากเดียวกัน คุณก็ยังคาดหวังว่าจะได้ขนม
ตอนนี้นำเรื่องนี้ไปคิดเหมือนกับโค้ดในโปรแกรม LSP บอกเราว่า ถ้าคุณออกแบบคลาส (กล่องขนม) หนึ่งๆ ให้สืบทอด (inherit) มาจากคลาสอื่น คุณควรจะสามารถใช้งานคลาสลูกราวกับว่ามันคือคลาสแม่ได้ โดยไม่ต้องรู้ว่ามันเป็นคลาสลูกจริงๆ
ประโยชน์ของ LSP มีมากมาย เช่น:
- รักษาความสม่ำเสมอ: ช่วยให้โค้ดของเราสม่ำเสมอและเข้าใจได้ง่ายขึ้น เพราะทำให้คุณรู้สึกมั่นใจว่าคลาสย่อยจะทำงานได้เหมือนคลาสหลักที่มันสืบทอดมา - ความยืดหยุ่น: LSP ทำให้เราสามารถเปลี่ยนแปลงคลาสได้โดยไม่เกิดผลกระทบต่อคลาสที่ใช้งานคลาสพวกนี้ - การบำรุงรักษา: ทำให้ระบบของเราง่ายต่อการบำรุงรักษา เพราะเราสามารถแน่ใจได้ว่าการเปลี่ยนแปลงใดๆ จะไม่ทำให้เกิดปัญหาที่คาดไม่ถึง
มาดูตัวอย่างโค้ดที่ง่ายที่สุดกัน:
class Bird:
def fly(self):
print("ฉันบินได้")
class Sparrow(Bird):
# นกกระจอกเทศสามารถบินได้
pass
class Ostrich(Bird):
# แต่นกกระจอกออสเตรเลียบินไม่ได้
def fly(self):
raise Exception("ฉันบินไม่ได้")
def letItFly(bird):
bird.fly()
sparrow = Sparrow()
ostrich = Ostrich()
# เรียกใช้ฟังก์ชันกับนกกระจอกเทศ
letItFly(sparrow) # Output: ฉันบินได้
# เรียกใช้ฟังก์ชันกับนกกระจอกออสเตรเลีย
# ตรงนี้จะทำให้เกิด Exception เพราะตัวละครสายพันธุ์นี้บินไม่ได้
# letItFly(ostrich) # จะทำให้เกิด Exception: ฉันบินไม่ได้
ในตัวอย่างนี้, ตามหลัก LSP, `Ostrich` ไม่ควรจะเป็น subclass ของ `Bird` เพราะมันทำให้เกิดข้อยกเว้น (Exception) เมื่อพยายามใช้งาน `fly()` ซึ่งไม่ถือเป็นการ "substitute" ที่ถูกต้องตามหลักของ `Bird` ดังนั้นควรแก้ไขโดยการสร้าง interface ให้ถูกต้อง:
class FlyingBird:
def fly(self):
print("ฉันบินได้")
class NonFlyingBird:
def walk(self):
print("ฉันเดินได้")
class Sparrow(FlyingBird):
pass
class Ostrich(NonFlyingBird):
pass
# ตัวอย่างการเรียกใช้
sparrow = Sparrow()
ostrich = Ostrich()
# นกกระจอกเทศบิน
sparrow.fly() # Output: ฉันบินได้
# นกกระจอกออสเตรเลียไม่ต้องใช้ฟังก์ชัน fly() เพราะมันไม่สามารถบินได้จริงๆ
ostrich.walk() # Output: ฉันเดินได้
ดังนั้นการพัฒนาโปรแกรมออบเจ็กต์ออเรนเต็ดโดยปฏิบัติตาม LSP ช่วยให้สามารถสร้างโค้ดที่สามารถร่วมงานกับโค้ดอื่นได้อย่างแนบเนียนโดยไม่เกิดปัญหาภายหลัง เป็นการลดความซับซ้อนในการจัดการโค้ดและเพิ่มความเป็นไปได้ในการขยายโปรแกรมในอนาคต
หากคุณต้องการศึกษาหลักการแห่งการเขียนโปรแกรมที่ดีอย่าง LSP ให้ดียิ่งขึ้น การเรียนรู้ผ่านโรงเรียนสอนโปรแกรมมิ่งที่มีคุณภาพเช่น EPT จะเป็นประโยชน์อย่างมาก ที่นี่คุณจะได้เรียนรู้พื้นฐานไปจนถึงการประยุกต์ใช้หลักการต่างๆ ให้กับโปรเจ็กต์จริงได้อย่างคล่องแคล่ว ซึ่งจะนำไปสู่การสร้างโปรแกรมที่มีคุณภาพและประสิทธิภาพสูงได้ไม่ยาก.
หมายเหตุ: ข้อมูลในบทความนี้อาจจะผิด โปรดตรวจสอบความถูกต้องของบทความอีกครั้งหนึ่ง บทความนี้ไม่สามารถนำไปใช้อ้างอิงใด ๆ ได้ ทาง EPT ไม่ขอยืนยันความถูกต้อง และไม่ขอรับผิดชอบต่อความเสียหายใดที่เกิดจากบทความชุดนี้ทั้งทางทรัพย์สิน ร่างกาย หรือจิตใจของผู้อ่านและผู้เกี่ยวข้อง
หากเจอข้อผิดพลาด หรือต้องการพูดคุย ติดต่อได้ที่ https://m.me/expert.Programming.Tutor/
Tag ที่น่าสนใจ: liskov_substitution_principle oop programming_principle inheritance object-oriented_programming flexibility code_design python subclass interface_design code_maintenance
หากมีข้อผิดพลาด/ต้องการพูดคุยเพิ่มเติมเกี่ยวกับบทความนี้ กรุณาแจ้งที่ http://m.me/Expert.Programming.Tutor
085-350-7540 (DTAC)
084-88-00-255 (AIS)
026-111-618
หรือทาง EMAIL: NTPRINTF@GMAIL.COM
Copyright (c) 2013 expert-programming-tutor.com. All rights reserved. | 085-350-7540 | 084-88-00-255 | ntprintf@gmail.com