ตามวิกิพีเดีย การเขียนโปรแกรมเชิงวัตถุ (OOP) เป็นกระบวนทัศน์การเขียนโปรแกรมตามแนวคิดของ "วัตถุ" ซึ่งสามารถมีข้อมูลและรหัส:ข้อมูลในรูปแบบของฟิลด์ (มักเรียกว่าแอตทริบิวต์หรือคุณสมบัติ) และรหัสในรูปแบบ ของขั้นตอนต่างๆ (มักเรียกว่า method)
Ruby เป็นภาษาเชิงวัตถุล้วนๆ ซึ่งหมายความว่าในภาษา Ruby ทุกอย่างเป็นวัตถุ อ็อบเจ็กต์เหล่านี้ ไม่ว่าจะเป็นสตริง ตัวเลข คลาส โมดูล ฯลฯ ทำงานในระบบที่เรียกว่า The Object Model .
Ruby เสนอวิธีการที่เรียกว่า object_id
ซึ่งสามารถใช้ได้กับวัตถุทั้งหมด ตัวระบุนี้ส่งคืนจำนวนเต็มและจะไม่เหมือนกันสำหรับสองอ็อบเจ็กต์ มาทำให้มือของเราสกปรกกันเถอะ คุณสามารถทำได้โดยพิมพ์ irb
ในเทอร์มินัลของคุณ
ดังที่เห็นด้านบน สตริง จำนวนเต็ม อาร์เรย์ คลาส และแม้แต่เมธอดล้วนเป็นอ็อบเจ็กต์ เนื่องจากมี ID อ็อบเจ็กต์
ในบทความนี้ เราจะกล่าวถึงแนวคิดต่อไปนี้โดยละเอียด:
- คลาสและอินสแตนซ์
- มรดก
- วิธีการสาธารณะ ส่วนตัว และได้รับการป้องกัน
- ส่วนผสม
- โมดูล
- ลำดับชั้นวัตถุ
คลาสและอินสแตนซ์
ใน Ruby คลาสคือตำแหน่งที่กำหนดคุณลักษณะและทัศนคติ (การกระทำ) ของวัตถุ หากวัตถุเป็นทรงกลม (แอตทริบิวต์) และควรจะสามารถพูดได้ (การกระทำ) เราสามารถบอกได้จากชั้นเรียนว่าเป็นของสิ่งนั้น เพราะแอตทริบิวต์และการกระทำเหล่านี้ถูกกำหนดให้เป็นสิ่งที่เรียกว่า วิธีการ ในคลาสนั้น อ็อบเจ็กต์ที่เป็นของคลาสเรียกว่า อินสแตนซ์ ของคลาสนั้นและสร้างขึ้น (ทันที) โดยใช้ .new
. มาเริ่มกันด้วยการสร้างคลาสที่ชื่อว่า Human
. ฉันคิดว่าเราทุกคนเป็นมนุษย์ ดังนั้นเรื่องนี้น่าจะสนุก
class Human
def initialize(name)
@name = name
end
end
เริ่มต้น วิธีการระบุข้อกำหนดสำหรับอินสแตนซ์ใหม่ของคลาสที่จะสร้าง ในกรณีข้างต้น เราจะเห็นได้ว่าการสร้างมนุษย์ใหม่จำเป็นต้องมีชื่อ ดังนั้น สามารถสร้างตัวอย่างใหม่ของมนุษย์ได้โดยใช้คำสั่ง Human.new(name)
ที่ชื่ออะไรก็ได้ที่คุณเลือก ในกรณีของเรา ให้ใช้ 'Henry' เพื่อทดสอบสิ่งนี้ในสภาพแวดล้อม irb ของเรา สิ่งที่เราต้องทำคือโหลดไฟล์โดยใช้คำสั่ง load './path_to_filename'
และใช้คำสั่งซ้ำเพื่อดำเนินการไฟล์ใหม่ทุกครั้งที่มีการเปลี่ยนแปลง ในกรณีของฉัน มันคือ load './Human.rb'
เนื่องจาก irb เปิดอยู่ในโฟลเดอร์ที่มีไฟล์ดังกล่าว ในการรันโค้ดโดยไม่ใช้ irb เราต้องเพิ่ม puts
คำสั่งก่อนทุกคำสั่งเพื่อให้เห็นผล
เมื่อเราพยายามสร้างมนุษย์ใหม่โดยไม่มีชื่อ เราจะได้รับข้อผิดพลาดในการโต้แย้งเนื่องจากจำเป็นต้องมีชื่อ แต่เมื่อเราทำถูกต้องแล้ว จะเห็นว่ามนุษย์ชื่อ Henry ถูกสร้างมาและอยู่ในกลุ่ม Human
. เฮนรี่จึงเป็นตัวอย่างของคลาส Human
.
@name
ตัวแปรถูกเรียกเป็นตัวแปรอินสแตนซ์เนื่องจาก @
สัญลักษณ์ที่ขึ้นต้นด้วย ซึ่งหมายความว่าตัวแปรนี้สามารถอ้างอิงได้โดยวิธีอื่นใดในคลาส ตราบใดที่อินสแตนซ์ของคลาสที่เป็นปัญหายังคงมีอยู่ ที่นี่ เราได้สร้างและตั้งค่าให้เท่ากับชื่อที่ใช้เริ่มต้นวัตถุ
มาดำเนินการกำหนดลักษณะและการกระทำของวัตถุใด ๆ ที่เป็นของคลาสนี้ เนื่องจากวัตถุที่สร้างขึ้นเรียกว่าอินสแตนซ์ของคลาส เมธอดที่กำหนดพฤติกรรมจึงเรียกว่า เมธอดอินสแตนซ์ . มนุษย์มีชื่อและส่วนต่างๆ ของร่างกายและสามารถดำเนินการบางอย่างได้ ดังนั้นมากำหนดกัน
def name
@name
end
def no_of_legs
2
end
def no_of_hands
2
end
def speak
'blablabla'
end
เราได้เพิ่มวิธีการที่เรียกชื่อของมนุษย์ที่สร้างขึ้น กำหนดจำนวนขาและมือที่มนุษย์มี และให้มนุษย์สามารถพูดได้ เราสามารถเรียกเมธอดเหล่านี้บนอินสแตนซ์ของคลาสได้โดยใช้ instance.method_name
ดังที่แสดงด้านล่าง
จะเกิดอะไรขึ้นถ้าเราเปลี่ยนใจและตัดสินใจว่าเราต้องการเปลี่ยนชื่อของเฮนรี่ในชั้นเรียนของเรา Ruby มีวิธีการในตัวที่เราสามารถทำได้ แต่ก็สามารถทำได้ด้วยตนเองเช่นกัน ด้วยตนเอง เราสามารถเปลี่ยนแปลง name method ของเราจากการเป็นเพียง getter method ที่ได้รับชื่อเป็น setter method ที่ตั้งค่าเป็นค่าด้วยถ้ามีให้
def name=(new_name)
@name = new_name
end
การใช้ attr_accessor
ในตัวของ Ruby วิธีเราสามารถละทิ้งวิธีการชื่อของเราและแทนที่ด้วยบรรทัด attr_accessor :name
:
class Human
attr_accessor :name
def initialize(name)
@name = name
end
# rest of the code
end
ไม่ว่าจะเลือกวิธีการใด สุดท้ายนี้คือสิ่งที่หาได้
วิธีการทั้งหมดที่สร้างขึ้นจนถึงขณะนี้เรียกว่า instance methods
เพราะสามารถเรียกได้ในทุกอินสแตนซ์ของคลาส แต่ไม่ใช่ตัวคลาสเอง นอกจากนี้ยังมีสิ่งที่เรียกว่า class method
ซึ่งสามารถเรียกใช้ในคลาสได้เอง ไม่ใช่ในอินสแตนซ์ ตั้งชื่อเมธอดของคลาสโดยนำหน้าชื่อเมธอดด้วย self.
. นี่คือตัวอย่าง:
# within the Human class
def self.introduction
"I am a human, not an alien!"
end
ดังที่เราเห็นข้างต้นว่า class method ใช้ได้เฉพาะกับ class เองเท่านั้น ไม่สามารถใช้กับ instance ได้ นอกจากนี้ เช่นเดียวกับตัวแปรอินสแตนซ์ เรามีตัวแปรคลาส ซึ่งนำหน้าด้วย @
สองตัว สัญลักษณ์ ตัวอย่างแสดงอยู่ด้านล่าง
class Human
attr_accessor :name
@@no_cars_bought = 0 #class variable
def initialize(name)
@name = name
end
def self.no_cars_bought
@@no_cars_bought
end
def buy_car
@@no_of_cars_bought += 1
"#{@name} just purchased a car"
end
end
ในตัวอย่างนี้ เราได้เพิ่ม buy_car
วิธีการเพื่อให้มนุษย์ทุกคนสามารถซื้อรถได้ นอกจากนี้เรายังได้สร้างตัวแปรคลาสที่เรียกว่า @@no_of_cars_bought
ที่จะเพิ่มขึ้น 1 ทุกครั้งที่มีการซื้อรถ สุดท้ายนี้ เราได้สร้างวิธีการเรียนที่เรียกว่า no_cars_bought
ที่ดึงจำนวนรถยนต์ที่ซื้อ มาดูกันว่ามันทำงานอย่างไร:
วิธีการทั้งหมดที่กำหนดไว้จนถึงขณะนี้เรียกว่า สาธารณะ เมธอดเพราะสามารถเข้าถึงได้จากภายนอกชั้นเรียน นอกจากนี้เรายังสามารถกำหนดวิธีการที่เรียกว่า ส่วนตัว เมธอดซึ่งสามารถเข้าถึงได้ภายในคลาสเท่านั้น ลองมาดูตัวอย่างกัน
# at the bottom of the Human class
def say_account_number
"My account number is #{account_number}"
end
private
def account_number
"1234567890"
end
ได้ผลลัพธ์ดังนี้:
เมื่อเราเรียก henry.account_number
เราได้รับ "NoMethodError" เพราะ account_number
เป็นเมธอดส่วนตัวที่สามารถเข้าถึงได้จากภายในคลาสเท่านั้น เมื่อเข้าใช้งานผ่าน say_account_number
อย่างที่เราทำ ไม่มีข้อผิดพลาด เนื่องจากวิธีนี้มีอยู่ในคลาสเดียวกับวิธีส่วนตัว สิ่งสำคัญคือต้องสังเกตว่าทุกอินสแตนซ์เมธอดหลัง private
คำหลักกลายเป็นวิธีการส่วนตัว ดังนั้นควรกำหนดเมธอดส่วนตัวที่ด้านล่างของคลาสหลังจากเมธอดสาธารณะทั้งหมด
คุณเคยได้ยินเกี่ยวกับ protected วิธีการ? ช่ายยย! สิ่งเหล่านี้ก็มีเช่นกัน แต่เราจะพูดถึงพวกเขาหลังจากที่เราเข้าใจแนวคิดของ มรดก .
มรดก
เมื่อเรารู้เกี่ยวกับคลาสและอินสแตนซ์แล้ว เรามาพูดถึงเรื่อง inheritance . กัน . เพื่อให้เข้าใจแนวคิดเรื่องการสืบทอดอย่างถูกต้อง เรามาสร้างคลาสใหม่ชื่อ Mammal
เนื่องจากมนุษย์เป็นสัตว์เลี้ยงลูกด้วยนม ฉันจำวลีหนึ่งในชั้นเรียนวิทยาศาสตร์ได้:"มนุษย์ทุกคนเป็นสัตว์เลี้ยงลูกด้วยนม แต่ไม่ใช่สัตว์เลี้ยงลูกด้วยนมทั้งหมดที่เป็นมนุษย์" ฉันยังจำได้ด้วยว่าลักษณะบางอย่างของสัตว์เลี้ยงลูกด้วยนมนั้นรวมถึงการมีขนหรือขนและสมองที่ซับซ้อน มาใส่ข้อมูลนี้ใน Mammal
ชั้นเรียน
class Mammal
def has_hair?
"Most certainly, Yes"
end
def has_complex_brain?
"Well, as a mammal, what do you expect?"
end
end
คุณจำวลีชั้นเรียนวิทยาศาสตร์ของฉันได้ไหม ถ้าเป็นเช่นนั้น เป็นสิ่งสำคัญที่เราจะต้องสร้างความสัมพันธ์ที่ยืนยันคำสั่งนี้ ดังนั้นสิ่งที่เราจะทำ? เราอนุญาตให้คลาสมนุษย์สืบทอดคุณสมบัติของ Mammal
คลาสโดยเพิ่ม < Mammal
เป็นคำจำกัดความของคลาส
class Human < Mammal
# all other code
end
คลาสที่สืบทอดคุณสมบัติของอีกคลาสหนึ่งเรียกว่า subclass และคลาสที่สืบทอดมานั้นเรียกว่า superclass . ในกรณีของเรา Human
เป็นคลาสย่อยและ Mammal
คือซุปเปอร์คลาส สิ่งสำคัญที่ควรทราบ ณ จุดนี้ หากคุณกำลังกำหนดคลาสทั้งหมดในไฟล์เดียวเหมือนที่เราทำอยู่ในขณะนี้ Mammal
คำจำกัดความของคลาสควรมาก่อน Human
ในไฟล์ของคุณ เนื่องจากเราไม่ต้องการอ้างถึงตัวแปรก่อนที่จะกำหนด มาดูกันว่าตอนนี้มนุษย์มีฟีเจอร์อะไรเพิ่มเติมบ้าง
ดังที่แสดงไว้ข้างต้น ขณะนี้มนุษย์สามารถเข้าถึงคุณลักษณะทั้งหมดที่กำหนดไว้ใน Mammal
ระดับ. หากเราลบมรดก (เช่น เราลบ < Mammal
จากโค้ดบรรทัดนั้น) และรันคำสั่ง henry.class.superclass
เราได้รับ "วัตถุ" เป็นคำตอบของเรา สิ่งนี้บอกเราว่าทุกคลาสเมื่อไม่ได้สืบทอดโดยตรงจากคลาสอื่นมีซูเปอร์คลาสเป็น "Object" ซึ่งช่วยเสริมความจริงที่ว่าใน Ruby แม้แต่คลาสก็เป็นวัตถุ
ตอนนี้เรารู้แล้วว่า superclasses คืออะไร คราวนี้ก็เป็นเวลาที่เหมาะสมที่จะพูดถึงคีย์เวิร์ด super . Ruby จัดเตรียมคีย์เวิร์ดนี้เพื่อเปิดใช้งานการใช้ซ้ำและแก้ไขเมธอดที่มีอยู่แล้วในซูเปอร์คลาส ใน Mammal
superclass จำได้ว่าเรามี method ที่เรียกว่า has_hair?
; จะเป็นอย่างไรถ้าเราต้องการเพิ่มข้อมูลเพิ่มเติมเฉพาะสำหรับมนุษย์ทุกครั้งที่มีการเรียกใช้เมธอดนั้น นี่คือที่มาของการใช้ super keyword ใน Human
. ของเรา class เรากำหนด method ที่มีชื่อเดียวกันว่า has_hair?
.
def has_hair?
super + ", but humans can be bald at times"
end
เมื่อเรียก super keyword แล้ว Ruby จะค้นหาชื่อเมธอดนั้นใน superclass และส่งคืนผลลัพธ์ ในวิธีการข้างต้น เราได้เพิ่มข้อมูลเพิ่มเติมให้กับผลลัพธ์ที่สร้างโดย has_hair?
ของ superclass วิธีการ
Ruby รองรับการสืบทอดคลาสเดียวเท่านั้น ซึ่งหมายความว่าคุณสามารถสืบทอดคุณสมบัติของคลาสจากคลาสเดียวเท่านั้น ฉันแน่ใจว่าคุณกำลังสงสัยว่าจะเกิดอะไรขึ้นถ้าคุณต้องการเพิ่มคุณสมบัติหลายรายการที่ไม่เฉพาะเจาะจงสำหรับชั้นเรียนเฉพาะในชั้นเรียนของคุณ Ruby ยังจัดเตรียมสิ่งนี้ในรูปแบบของ mixins แต่ก่อนจะพูดถึงเรื่องนี้ เรามาพูดถึง วิธีป้องกัน . กันก่อน .
วิธีป้องกัน
เมธอดที่ได้รับการป้องกันทำงานเหมือนกับเมธอดส่วนตัวที่เรียกใช้งานได้ภายในคลาสและคลาสย่อย มาสร้างวิธีการป้องกันภายใน Mammal
ชั้นเรียน
#at the bottom of the Mammal class
def body_status
body
end
protected
def body
"This body is protected"
end
ดังที่แสดงไว้ข้างต้น เราไม่สามารถเข้าถึง body
วิธีเพราะมีการป้องกัน อย่างไรก็ตาม เราสามารถเข้าถึงได้จาก body_status
method ซึ่งเป็นอีกวิธีหนึ่งใน Mammal
ระดับ. เรายังสามารถเข้าถึงเมธอดที่ได้รับการป้องกันจากคลาสย่อยของคลาสที่กำหนดไว้ มาลองทำกันใน Human
ชั้นเรียน
# within the Human class
def check_body_status
"Just a human checking that " + body.downcase
end
ดังที่แสดงไว้ข้างต้น ไม่ว่าจะกำหนดวิธีการของร่างกายภายใน Human
คลาสและได้รับการป้องกัน Human
class สามารถเข้าถึงได้เพราะเป็น subclass ของ Mammal
ระดับ. การเข้าถึงคลาสย่อยนี้สามารถทำได้ด้วยเมธอดส่วนตัว อย่างไรก็ตาม สิ่งนี้นำไปสู่คำถามว่าวิธีการเหล่านี้มีความแตกต่างกันอย่างไร
วิธีการป้องกันสามารถเรียกได้โดยใช้ตัวรับที่ชัดเจน เช่น receiver.protected_method
ตราบใดที่ผู้รับที่เป็นปัญหาคือคำหลัก self
หรืออยู่ในคลาสเดียวกับ self
. อย่างไรก็ตาม วิธีส่วนตัวสามารถเรียกได้โดยใช้ตัวรับที่ชัดเจนก็ต่อเมื่อผู้รับที่ชัดเจนคือ self
มาแก้ไขโค้ดของเราโดยแทนที่ body.downcase
ด้วย self.body.downcase
ใน check_body_status
เมธอดและเปลี่ยนการเรียกเมธอดส่วนตัวของเราให้รวม self
.
def check_body_status
"Just a human checking that " + self.body.downcase
# body method is protected
end
def say_account_number
"My account number is #{self.account_number}"
# account_number method is private
end
ป.ล. ก่อน Ruby 2.7 เมื่อเรียกใช้เมธอดส่วนตัวเพื่อรับข้อมูลบางอย่างโดยใช้ self
เป็นไปไม่ได้
มาแทนที่คำว่า self
. กัน ด้วยวัตถุในคลาสเดียวกับ self
. ในกรณีของเรา self
คือ Henry
ที่กำลังเรียกใช้เมธอด และ Henry
เป็นตัวอย่างของ Human
คลาสที่สืบทอดมาจาก Mammal
ชั้นเรียน
def check_body_status
non_self = Human.new('NotSelf') #same class as self
puts "Just #{non_self.name} checking that " + non_self.body.downcase
# Mammal.new is also in the same class as self
"Just a human checking that " + Mammal.new.body.downcase
end
def say_account_number
non_self = Human.new('NotSelf')
"My account number is #{non_self.account_number}"
end
ดังที่แสดงไว้ข้างต้น สามารถแทนที่ self
. ได้ ในเมธอดที่ได้รับการป้องกันด้วยอ็อบเจ็กต์ของคลาสเดียวกับ self
แต่วิธีนี้เป็นไปไม่ได้ด้วยวิธีการส่วนตัว
ส่วนผสม
มิกซ์อินคือชุดของโค้ดที่กำหนดไว้ใน โมดูล ซึ่งเมื่อรวมอยู่ในหรือขยายไปยังชั้นเรียนใด ๆ แล้ว ให้ความสามารถเพิ่มเติมแก่ชั้นเรียนนั้น สามารถเพิ่มโมดูลหลายโมดูลในคลาสได้ เนื่องจากไม่มีข้อจำกัดในเรื่องนี้ ซึ่งแตกต่างจากที่ได้รับจากการสืบทอดคลาส จากข้อมูลนี้ เรามาสร้างโมดูลที่ชื่อว่า Movement
เพื่อเพิ่มความสามารถในการเคลื่อนไหวให้กับคลาสมนุษย์
module Movement
def hop
"I can hop"
end
def swim
"Ermmmm, I most likely can if I choose"
end
end
ขั้นตอนต่อไปคือการรวมโมดูลนี้ไว้ใน Human
. ของเรา ระดับ. ทำได้โดยการเพิ่มวลี include <module_name>
ถึงชั้นเรียนที่เป็นปัญหา ในกรณีของเรา สิ่งนี้จะนำมาซึ่งการเพิ่ม include Movement
แก่ชนชั้นมนุษย์ดังแสดงข้างล่างนี้
class Human < Mammal
include Movement
# rest of the code
end
มาทดสอบโค้ดนี้กัน:
ดังที่แสดงไว้ข้างต้น เมธอดที่ผสมลงในคลาสผ่านโมดูลจะใช้ได้เฉพาะกับอินสแตนซ์ของคลาสเท่านั้น ไม่ใช่ตัวคลาสเอง จะเป็นอย่างไรถ้าเราต้องการทำให้เมธอดในโมดูลพร้อมใช้งานในคลาสและไม่ใช่อินสแตนซ์ ในการทำเช่นนี้ เราจะแทนที่คำว่า "รวม" ด้วย "ขยาย" เช่นเดียวกับใน extend Movement
.
.extend
สามารถใช้เทอมกับอินสแตนซ์ของคลาสได้ แต่ในลักษณะที่แตกต่างกันมาก มาสร้างโมดูลอื่นที่เรียกว่า Parent
.
module Parent
def has_kids?
"most definitely"
end
end
ดังที่แสดงด้านบน โดยใช้ .extend(Parent)
ในตัวแปร dad ทำให้ has_kids?
วิธีการที่มีอยู่ สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อเราไม่ต้องการให้เมธอดของโมดูลผสมกันในทุกอินสแตนซ์ของคลาส ดังนั้น extend
สามารถใช้ได้เฉพาะกรณีที่เราสนใจเท่านั้น
โมดูล
โมดูลเป็นที่อยู่อาศัยสำหรับคลาส เมธอด ค่าคงที่ และแม้กระทั่งโมดูลอื่นๆ นอกเหนือจากการใช้เป็นมิกซ์อิน อย่างที่เห็นก่อนหน้านี้ โมดูลมีประโยชน์อื่น ๆ เป็นวิธีที่ยอดเยี่ยมในการจัดระเบียบโค้ดของคุณเพื่อป้องกันชื่อไม่ให้ขัดแย้งกัน เนื่องจากมีข้อดีที่เรียกว่า เนมสเปซ ใน Ruby ทุกคลาสเป็นโมดูล แต่ไม่มีโมดูลใดเป็นคลาส เนื่องจากโมดูลไม่สามารถสร้างอินสแตนซ์หรือสืบทอดได้ เพื่อให้เข้าใจเนมสเปซ ให้สร้างโมดูลที่มีค่าคงที่ คลาส เมธอด และโมดูลอื่น
module Male
AGE = "Above 0"
class Adult
def initialize
puts "I am an adult male"
end
end
def self.hungry
puts "There's no such thing as male food, I just eat."
end
module Grown
def self.age
puts "18 and above"
end
end
end
คุณอาจสังเกตเห็นว่าวิธีการที่กำหนดและเรียกใช้ภายในโมดูลด้านบนนั้นนำหน้าด้วย self
. นี่เป็นเพราะว่าโมดูลไม่สามารถสร้างอินสแตนซ์ได้ และเมธอดใดๆ ที่กำหนดไว้ภายในโมดูลนั้น โดยไม่มี self
คำนำหน้าจะใช้ได้เป็นมิกซ์อินเท่านั้น ดังที่เราเห็นก่อนหน้านี้เมื่อเราพูดถึง mixins
. ในการเรียกใช้เมธอดในโมดูลนั้น เราต้องระบุสิ่งนี้ในชื่อเมธอดโดยใช้ self.method_name
. จำได้ว่าเรายังใช้ self
คีย์เวิร์ดในคลาสเมธอด หลักการเดียวกันนี้ใช้ที่นี่
ดังที่แสดงไว้ข้างต้น ในการเข้าถึงคลาส โมดูล หรือค่าคงที่ที่กำหนดไว้ภายในโมดูล เราใช้ module_name::target_name
. เพื่อให้เข้าใจแนวคิดเนมสเปซอย่างถูกต้อง เราจะสร้างโมดูลอื่นที่มีคลาสชื่อ Adult
แล้วมาดูกันว่าทั้งสองคลาสมีความแตกต่างกันอย่างไร
module Female
class Adult
def initialize
puts "I am an adult female"
end
end
def self.hungry
puts "Maybe there's such a thing as female food, I'm not sure. I just need to eat"
end
end
ดังที่แสดงไว้ข้างต้น เรามีสองชั้นเรียนที่มีชื่อ "ผู้ใหญ่" โดยการรวมไว้ในโมดูลของตนเอง เราสามารถใช้ชื่อเหล่านี้ได้โดยไม่สับสนเกี่ยวกับคลาสสำหรับผู้ใหญ่ที่ถูกเรียกในแต่ละครั้ง นอกจากนี้ โค้ดของเราอ่านง่ายและมีระเบียบมากขึ้น และเราใช้การแยกหลักการออกแบบข้อกังวล ขณะที่เราแยกบล็อคโค้ดต่างๆ ออกเป็นหมวดหมู่ต่างๆ ตามฟังก์ชัน
ลำดับชั้นของออบเจ็กต์
การเข้าใจคลาส อินสแตนซ์ โมดูล และแนวคิดเรื่องการสืบทอดนั้นน่าทึ่งมาก แต่ความรู้ในด้านนี้ยังไม่สมบูรณ์หากไม่เข้าใจลำดับชั้นของออบเจ็กต์ใน Ruby หมายถึงลำดับการค้นหาเมธอดใน Ruby มีวิธีการบางอย่างที่ช่วยให้เราเข้าใจลำดับชั้นนี้ หนึ่งในนั้นคือ ancestors
กระบวนการ. เมธอดนี้ไม่สามารถใช้ได้กับอินสแตนซ์ของคลาส แต่สามารถเรียกบนคลาสเองและบรรพบุรุษได้ ตัวอย่างแสดงอยู่ด้านล่าง
จากผลของ Human.ancestors
เราเห็นว่าเมธอดนี้ส่งคืนคลาสที่เป็นปัญหา รวมโมดูลโดยตรง คลาสพาเรนต์ และคลาสของพาเรนต์รวมโมดูลโดยตรง วนซ้ำนี้ต่อไปจนกว่าจะถึง Basic Object
ซึ่งเป็นรากของวัตถุทั้งหมด
อีกวิธีหนึ่งที่ใช้ได้เพื่อรับข้อมูลเพิ่มเติมเกี่ยวกับคลาสคือเมธอด included_modules
.
ดังที่แสดงไว้ข้างต้น คลาสมนุษย์มีสองโมดูลที่รวมอยู่ในนั้น:โมดูลที่เรารวมโดยตรงโดยใช้ include Movement
และสิ่งที่รวมอยู่ในคลาสอ็อบเจ็กต์ ซึ่งหมายความว่าแต่ละคลาสจะสืบทอดคุณสมบัติของคลาสจากคลาสบรรพบุรุษ และแต่ละโมดูลที่รวมอยู่ในนั้นจะถูกรวมเข้าด้วย จากข้อมูลนี้ เราจะทำแบบฝึกหัดง่ายๆ เพื่อยืนยันเส้นทางการค้นหาเมธอดใน Ruby และคลาสใดที่มีลำดับความสำคัญ เหนือผู้อื่นในเส้นทางนี้ เราจะกำหนดเมธอดที่มีชื่อเดียวกันแต่มีสตริงเอาต์พุตต่างกันและวางไว้ใน Human
คลาส Movement
โมดูล และ Mammal
ชั้นเรียน
# in the mammal class
def find_path
"Found me in the Mammal class path"
end
# in the Movement module
def find_path
"Found me in the Movement module path"
end
# in the Human class
def find_path
"Found me in the Human class path"
end
มาทำแบบฝึกหัดนี้กัน
ดังที่แสดงไว้ข้างต้น ลำดับการวางบรรพบุรุษเมื่อเราเรียก .ancestors
บนคลาสคือพาธที่ตามมาเมื่อมองหาเมธอดที่เรียกใช้บนอินสแตนซ์ของคลาสนั้น สำหรับ Human
ตัวอย่างคลาสที่เราสร้างขึ้น Ruby ค้นหาเมธอดในคลาสก่อน หากไม่พบ จะไปยังโมดูลที่รวมโดยตรง หากไม่พบ มันจะไปยังซูเปอร์คลาสและวงจรจะดำเนินต่อไปจนกว่าจะถึง BasicObject
. หากไม่พบวิธีการที่นั่น แสดงว่า "NoMethodError" ถูกส่งกลับ โดยใช้ .ancestors
เมธอด เราสามารถระบุเส้นทางการค้นหาสำหรับออบเจ็กต์และตำแหน่งของเมธอดที่เล็ดลอดออกมาจากจุดใดก็ได้
Ruby ยังเสนอวิธีการที่เรียกว่า methods
โดยที่เราสามารถระบุวิธีการทั้งหมดที่มีให้กับวัตถุใดก็ได้ เรายังสามารถทำการลบเพื่อแสดงว่าอันไหนมาจากพาเรนต์และอันไหนที่แปลกสำหรับมัน ตัวอย่างแสดงอยู่ด้านล่าง
ดังที่แสดงไว้ข้างต้น ตัวแปร Henry มีวิธีการมากมาย อย่างไรก็ตาม เมื่อเราลบออกจากสิ่งที่มีอยู่ใน Object คลาส เราพบว่าเราเหลือเฉพาะที่เรากำหนดไว้โดยเฉพาะในไฟล์ของเรา และวิธีการอื่น ๆ ทุกวิธีได้รับการสืบทอด สิ่งนี้จะเหมือนกันสำหรับทุกอ็อบเจ็กต์ คลาสของมัน และบรรพบุรุษของมัน ทำให้มือของคุณสกปรกได้โดยลองใช้ชุดค่าผสมต่างๆ ที่เกี่ยวข้องกับ Human.methods , Mammal.methods , Module.methods และคลาสหรือโมดูลอื่นๆ ที่กำหนดไว้ก่อนหน้านี้ คุณจะพบว่าสิ่งนี้ช่วยให้คุณเข้าใจโมเดลวัตถุ Ruby มากขึ้น