Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

หยุดใช้งบกรณีใน Ruby

คุณใช้ 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 เพื่อตรวจสอบประเภทคลาส . แต่คุณควรใช้ประโยชน์จาก ความหลากหลาย .

ซึ่งจะช่วยให้คุณสร้างโค้ดที่ดีขึ้นซึ่งสามารถขยายได้โดยการเพิ่มโค้ดใหม่แทนการเปลี่ยนโค้ดที่มีอยู่ ตอนนี้ถึงตาคุณที่จะดำเนินการและปรับโครงสร้างใหม่ 🙂

แต่นี่ไม่ได้หมายความว่าฉันกำลังสนับสนุนให้กำจัดคำชี้แจงของเคสทั้งหมดออกจากกล่องเครื่องมือของคุณ แต่คุณควรระมัดระวังเมื่อใดก็ตามที่คุณพบว่าตัวเองกำลังเขียน ตรวจสอบให้แน่ใจว่าเป็นวิธีแก้ปัญหาที่ดีที่สุด

อย่าลืม แชร์บทความนี้ ถ้าคุณต้องการให้ฉันเขียนบทความแบบนี้ต่อไป!