คุณใช้ OOP อย่างเต็มประสิทธิภาพ (Object-Oriented Programming) หรือคุณพลาดไปหรือเปล่า
หากคุณกำลังตัดสินใจตามประเภทของออบเจ็กต์ คุณจะพลาดฟีเจอร์ OOP ที่สำคัญอย่างหนึ่ง นั่นคือ ความหลากหลาย
การตัดสินใจประเภทมักจะทำในคำสั่ง case (ซึ่งไม่เป็นมิตรกับ OO) และในบทความนี้ คุณจะได้เรียนรู้วิธีเขียนโค้ดที่ดีขึ้นโดยการลบออก
การตรวจสอบประเภท
ให้ฉันเริ่มต้นด้วยการแสดงตัวอย่างที่เราไม่ใช้ประโยชน์จากความหลากหลาย
เราต้องการใช้เกม "Rock, Paper, Scissors" และเราได้ตัดสินใจที่จะมี Game
หนึ่งเกม คลาสและหนึ่งคลาสสำหรับทุกการเคลื่อนไหวที่เป็นไปได้
ในการตรวจสอบผู้ชนะ เราจะใช้ play
วิธีการใน Game
:
class Game def self.play(move1, move2) return :tie if move1 == move2 move1.wins_against?(move2) end end
และนี่คือหนึ่งในการเคลื่อนไหว (ส่วนอื่นๆ ทำตามรูปแบบเดียวกัน):
class Rock def wins_against?(other_move) case other_move when Paper then false when Scissors then true end end end
ตอนนี้เราสามารถเรียก play
วิธีที่มีสองกระบวนท่า &เราจะรู้ว่าการย้ายครั้งแรกชนะหรือไม่
p Game.play(Rock.new, Paper.new) # false
โอเค มันใช้ได้ แต่เราจะทำให้ดีกว่านี้ได้ไหม เราจะกำจัดคำแถลงกรณีที่น่าเกลียดนั้นออกไปได้ไหม
Polymorphism แทนการตรวจสอบประเภท
ใช่! เราสามารถกำจัดคำสั่ง case-checking case ได้โดยใช้พื้นฐานของ OOP
แนวคิดคือการใช้ความจริงที่ว่าเรารู้จักคลาสปัจจุบันเพื่อถามวัตถุเคลื่อนไหวอื่น ๆ ว่าสามารถเอาชนะเราได้หรือไม่
และเราจะใช้ชื่อเมธอดเฉพาะสำหรับคลาสของเรา (สำหรับ Rock
ชื่อเมธอดอาจเป็น:do_you_beat_rock?
)
ใน Ruby ความหลากหลายคือความสามารถในการส่งการเรียกเมธอด (หรือที่เรียกว่าข้อความ ในภาษา OOP) ไปยังอ็อบเจกต์ใดๆ โดยไม่ต้องตรวจสอบคลาสของอ็อบเจ็กต์ นี้เรียกอีกอย่างว่า "พิมพ์เป็ด" แต่ฉันไม่ชอบคำนั้น 🙂
ใน Java (อดทนกับฉันสักครู่…) คุณมีบางสิ่งที่เรียกว่า "อินเทอร์เฟซ" ซึ่งช่วยให้คุณบังคับชุดของวิธีการที่จะนำไปใช้โดยคลาสที่ระดับคอมไพเลอร์
เราไม่มีสิ่งนั้นใน Ruby (อาจจะดีกว่า) ดังนั้นคุณจะต้องพึ่งพาการทดสอบ
มาดูตัวอย่างโค้ดของการใช้งานใหม่นี้กัน:
class Rock def wins_against?(other_move) other_move.do_you_beat_rock? end def do_you_beat_paper? false end def do_you_beat_scissors? true end end
สังเกตว่าคำชี้แจงกรณีหายไปอย่างไร มันถูกแทนที่ด้วยการเรียกเมธอดเดียว &นิยามเมธอดสองเมธอด
อัปเดต :ตามที่ผู้อ่านบางคนแสดงความคิดเห็น ฉันไม่ได้สังเกตว่าตรรกะจะกลับกันเมื่อใช้รูปแบบนี้ ทางออกหนึ่งที่เสนอโดย Daniel P. Clark คือเพียงแค่พลิกคำสั่งใน
play
วิธีการmove2.wins_against?(move1)
.
นี่ไม่สะอาดกว่านี้เหรอ? คุณคิดอย่างไร?
อีกหนึ่งก้าว!
สมมติว่าคุณต้องการเพิ่มการย้ายใหม่ ต้องเปลี่ยนอะไรบ้าง
คิดสักนิด…
ด้วยแนวทางคำสั่ง case คุณต้องเพิ่มสาขาใหม่ในทุกการเคลื่อนไหว สังเกตว่าคุณ “ถูกบังคับ” ให้เปลี่ยนวิธีการทำงานที่สมบูรณ์แบบเพื่อแนะนำฟังก์ชันใหม่
แต่นั่นไม่ใช่ปัญหาสำหรับเวอร์ชันที่เน้น OOP มากกว่าของเรา สิ่งที่เราต้องทำคือเพิ่มวิธีการใหม่ นี่คือหลักการเปิด/ปิด (ตัว “O” ใน SOLID) ในการใช้งานจริง
อีกทางเลือกหนึ่งคือใช้ metaprogramming (ด้วย method_missing
หรือ define_method
)
ฉันจะใช้ metaprogramming สำหรับสิ่งนี้จริงหรือไม่
อาจจะไม่ เว้นแต่จำนวนการเคลื่อนไหวจะเปลี่ยนแปลงตลอดเวลา หรือมีการเคลื่อนไหวจำนวนมาก
metaprogramming มีค่าใช้จ่าย ไม่ใช่สัญลักษณ์แสดงหัวข้อย่อยสีเงินอย่างที่บางคนอาจเชื่อ คุณจะซื้อขายได้อย่างมีประสิทธิภาพและอ่านง่ายเพื่อเพิ่มความยืดหยุ่น
บทสรุป
ในบทความนี้ คุณได้เรียนรู้ว่าคุณควร หลีกเลี่ยงการใช้ case statement เพื่อตรวจสอบประเภทคลาส . แต่คุณควรใช้ประโยชน์จาก ความหลากหลาย .
ซึ่งจะช่วยให้คุณสร้างโค้ดที่ดีขึ้นซึ่งสามารถขยายได้โดยการเพิ่มโค้ดใหม่แทนการเปลี่ยนโค้ดที่มีอยู่ ตอนนี้ถึงตาคุณที่จะดำเนินการและปรับโครงสร้างใหม่ 🙂
แต่นี่ไม่ได้หมายความว่าฉันกำลังสนับสนุนให้กำจัดคำชี้แจงของเคสทั้งหมดออกจากกล่องเครื่องมือของคุณ แต่คุณควรระมัดระวังเมื่อใดก็ตามที่คุณพบว่าตัวเองกำลังเขียน ตรวจสอบให้แน่ใจว่าเป็นวิธีแก้ปัญหาที่ดีที่สุด
อย่าลืม แชร์บทความนี้ ถ้าคุณต้องการให้ฉันเขียนบทความแบบนี้ต่อไป!