สวัสดีเด็กๆ และพ่อแม่ อืม นักพัฒนา Ruby ในบทความก่อนหน้า เราได้ดำดิ่งสู่ ancestry chain ในบทความวันนี้ เราจะดำดิ่งลึกเข้าไปในการเป็นพ่อแม่และการสืบทอด (inheritance) เราจะสำรวจ inherited hook method และดูการป้องกันการสืบทอด
เมื่อลูกสืบทอด 101: The Inherited Hook Method
เริ่มด้วยการดูว่าการเป็นพ่อแม่ถูกประกาศอย่างไร Ruby 提供วิธีที่สะดวกในการโต้ตอบกับคลาสเมื่อมันถูกประกาศเป็นพ่อแม่ของอีกคลาสหนึ่ง
class Parent def self.inherited(subclass) puts "#{subclass} inherits from Parent" end end class Child < Parent endการรันโค้ดนี้จะพิมพ์ "Child inherits from Parent" เนื่องจากเมธอด Parent.inherited ถูกเรียกเมื่อคลาส Child สืบทอดจาก Parent โปรดสังเกตว่าเมธอดนี้รับ subclass เป็นพารามิเตอร์—Child ในกรณีนี้ กลไกนี้ช่วยให้คุณโต้ตอบกับคลาส Parent เพื่อกำหนดชุดพฤติกรรมเฉพาะก็ต่อเมื่อมันถูกสืบทอด โดยพฤติกรรมในบริบทนี้ หมายถึงการแก้ไข กำหนด หรือลบ ตัวแปร เมธอด และค่าคงที่บนคลาสที่สืบทอดหรือถูกสืบทอด
ตอนนี้ มากำหนดเมธอด parent_name แบบ on-the-fly:
class Parent def self.inherited(subclass) subclass.define_method :parent_name do "Daddy" end end end class Child < Parent end Child.new.parent_name # => "Daddy"ที่นี่ เรากำหนดเมธอดบนคลาส Child เมื่อมันสืบทอดจาก Parent แต่โดยไม่เพิ่มเมธอดนั้นโดยตรงไปที่คลาส Parent แทนที่จะเป็นเช่นนั้น มันถูกกำหนดเฉพาะเมื่ออีกคลาสหนึ่งสืบทอดจาก Parent
ดีแล้ว เราครอบคลุมทฤษฎีแล้ว ตอนนี้ มาดูตัวอย่างที่เป็นจริงมากขึ้นในชีวิตของนักพัฒนา Ruby
ป้องกันการสืบทอดคลาส
ใน Ruby on Rails การย้ายฐานข้อมูล (database migrations) จัดการโดยคลาส ActiveRecord::Migration ลองสืบทอดจากคลาสนี้โดยตรง
class AddFirstnameToUsers < ActiveRecord::Migration end # => StandardError (Directly inheriting from ActiveRecord::Migration is not supported..)ข้อผิดพลาดนี้ถูก raise เพราะ Ruby on Rails มีกลไกที่ป้องกันไม่ให้เราสืบทอดจากคลาสนี้ ทำไม Ruby on Rails จึง implement กลไกนี้?
Migration ผูกมัดอย่างแน่นกับเวอร์ชันเฉพาะของ Ruby on Rails จริงๆ แล้ว API ที่ให้โดยคลาสนี้อาจเปลี่ยนแปลงเล็กน้อยระหว่าง 2 เวอร์ชัน ดังนั้น เพื่อหลีกเลี่ยงการทำลาย migrations เมื่อคุณอัปเกรด Ruby on Rails เฟรมเวิร์กบังคับให้คุณเลือกเวอร์ชันเฉพาะของคลาส ActiveRecord::Migration นี่รับประกันการทำงานราบรื่นของ migrations ของคุณ
class AddFirstnameToUsers < ActiveRecord::Migration[4.2] endในตัวอย่างข้างต้น migration ของเราผูกมัดกับ API ActiveRecord::Migration ที่ให้มาพร้อมกับเวอร์ชัน 4.2 ของ Ruby on Rails ดังนั้น แม้เราจะอัปเกรดแอปเป็นเวอร์ชัน 5.0 migrations ของเราจะยังทำงานราบรื่นเพราะมันยังคงรันกับ API เวอร์ชัน 4.2 ของ ActiveRecord::Migration
การป้องกันการสืบทอดทำงานอย่างไร
ตอนนี้เราเข้าใจ ทำไม การสืบทอดถูกป้องกันที่นี่ มาดู อย่างไร ActiveRecord::Migration ป้องกันการสืบทอด ทุกตรรกะถูกกำหนดในเมธอด ActiveRecord::Migration.inherited
class AddFirstnameToUsers < ActiveRecord::Migration[4.2] endเมื่อคลาส AddFirstnameToUsers ของเราสืบทอดจาก ActiveRecord::Migration เมธอด hook ActiveRecord::Migration.inherited ถูกเรียก
module ActiveRecord class Migration def self.inherited(subclass) #:nodoc: super if subclass.superclass == Migration raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \ "Please specify the Rails release the migration was written for:\n" \ "\n" \ " class #{subclass} < ActiveRecord::Migration[4.2]" end end end endเช่นเราเห็น เมธอด hook นี้ตรวจสอบว่าคลาสย่อย (AddFirstnameToUsers) สืบทอดโดยตรงจาก ActiveRecord::Migration หากใช่ จะ raise error นี่คือ entry point ที่สมบูรณ์สำหรับการควบคุมการสืบทอด
สรุป
วันนี้ เราครอบคลุมพื้นฐานของการสืบทอดและการป้องกันการสืบทอด เราครอบคลุม inherited hook method และเห็นว่ามันมีประโยชน์มากเมื่อโต้ตอบกับคลาสที่สืบทอด/ถูกสืบทอด on-the-fly
ในการตั้งค่าจริง ให้ระมัดระวังเมื่อเล่นกับการสืบทอด ให้ระมัดระวังมากเมื่อคุณลบหรือ override เมธอดหรือคลาสที่มีอยู่ นี่อาจทำให้เกิด side effects ที่ไม่พึงประสงค์ ลูกๆ อาจหยุดเรียกคุณว่า daddy
Et Voilà บทความวันจบสิ้นสุดที่นี่!