ออบเจ็ค ในภาษา Ruby
ในบทนี้ เราจะแนะนำให้คุณรู้จักกับออบเจ็คในภาษา Ruby เราได้เขียนบทนี้ก่อนเนื่องจากว่า Ruby นั้นเป็นภาษาเขียนโปรแกรมเชิงวัตถุอย่างสมบูรณ์ และทุกอย่างในภาษา Ruby นั้นเป็นออบเจ็ค ดังนั้นการเข้าใจแนวคิดของออบเจ็คสามารถช่วยให้คุณเรียนรู้บทที่เหลือได้เร็วขึ้น และนี่เป็นเนื้อหาที่เราจะพูดถึงในบทนี้
- Ruby กับออบเจ็ค
- การสร้างออบเจ็ค
- Ruby object hierarchy
- Ruby top-level
Ruby กับออบเจ็ค
ภาษา Ruby นั้นเป็นภาษาเขียนโปรแกรมเชิงวัตถุที่เรียบง่ายและมีประสิทธิภาพ มันสามารถประมวลผลข้อความได้เป็นอย่างดีเหมือนกับภาษา Perl และทุกอย่างในภาษา Ruby นั้นเป็นออบเจ็คเหมือนกับภาษา Smalltalk
เมื่อคุณทำงานกับ Ruby คุณจะต้องเข้าใจก่อนว่าทุกอย่างในภาษา Ruby นั้นถูกสร้างมาจากออบเจ็ค แม้แต่ข้อมูล Literal พื้นฐานอย่างเช่น ตัวเลข สตริง วันที่ เมธอด หรือโมดูล ทุกอย่างต่างก็เป็นออบเจ็คทั้งนั้น ลองพิจารณาตัวอย่างด้านล่างนี้
p 1
p 5.4
p "Ruby"
p true
p [1, 2, 3]
ในตัวอย่าง เป็นการแสดงข้อมูลประเภทต่างๆ ในภาษา Ruby ซึ่งถ้าหากคุณมาจากภาษา PHP หรือ Perl ข้อมูลเหล่านี้จะเป็นเพียง Literal ของตัวเลข สตริง และ boolean เท่านั้น แต่สำหรับในภาษา Ruby แล้ว Literal เหล่านี้เป็นออบเจ็ค
p 1.class
p 5.4.class
p "Ruby".class
p true.class
p [1, 2, 3].class
เนื่องจากมันเป็นออบเจ็ค ทำให้เราสามารถเรียกใช้งานเมธอดของมันได้ จากตัวอย่าง ทั้ง 1
หรือ Ruby
นั้นต่างก็เป็นออบเจ็ค instance ซึ่งโดยทั่วไปแล้ว ทุกออบเจ็คจะถูกสร้างมาจากคลาสเสมอ เราเรียกใช้งานเมธอด class
จากออกเจ็คโดยการใส่เครื่องหมาย .
(จุด) ระหว่างออบเจ็คและชื่อของเมธอด ด้วยรูปแบบ: object.method
Integer
Float
String
TrueClass
Array
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม เราเรียกใช้เมธอด class
จากออบเจ็คประเภทต่างๆ เพื่อดูประเภทหรือคลาสของแต่ละออบเจ็ค
ต่อไปเป็นตัวอย่างการใช้งานเมธอดของออบเจ็คชนิดต่างๆ ในภาษา Ruby โดยทั่วไปแล้วออบเจ็คทุกประเภท จะมีเมธอดที่สร้างไว้แล้วที่เราสามารถใช้งานได้ เพื่ออำนวยความสะดวกในการจัดการกับออบเจ็คดังกล่าว
str = "Ruby"
p str.length
p str.downcase
p str.upcase
p str.reverse
num = 3
p num.to_f
p num.to_s
p num.even?
p num.odd?
ในตัวอย่าง เรามีตัวแปร str
ซึ่งเป็นออบเจ็คจากคลาส String
และเรียกใช้งานเมธอด length
เพื่อหาความยาวของข้อความ เมธอด downcase
เพื่อแปลงข้อความให้เป็นตัวพิมพ์เล็ก เมธอด upcase
เพื่อแปลงข้อความให้เป็นตัวพิมพ์ใหญ่ และเมธอด reverse
เพื่อแปลงข้อความย้อนกลับ
นอกจากนี้เรามีตัวแปร num
ซึ่งเป็นออบเจ็คจากคลาส Integer
เราใช้เมธอด to_i
เพื่อแปลงตัวเลขเป็นตัวเลขทศนิยม เมธอด to_s
เพื่อแปลงตัวเลขเป็นข้อความ เมธอด even?
เพื่อตรวจสอบว่าตัวเลขเป็นจำนวนคู่หรือไม่ และเมธอด odd?
เพื่อตรวจสอบว่าตัวเลขเป็นจำนวนคี่หรือไม่
String
4
"ruby"
"RUBY"
"ybuR"
Integer
3
"3"
false
true
นี่เป็นผลลัพธ์การทำงานของโปรแกรมจากการเรียกใช้งานเมธอดของออบเจ็คแต่ละประเภท จะเห็นว่าออบเจ็คแต่ละประเภทต่างก็มีเมธอดสำหรับจัดการข้อมูลที่แตกต่างกันไป ซึ่งเมธอดเหล่านี้ได้ถูกกำหนดไว้ในคลาสของออบเจ็คนั่นเอง
จากตัวอย่างด้านบน เป็นการใช้งานเมธอดเพียงบางส่วนเท่านั้น คุณสามารถเรียกใช้เมธอด methods
บนออบเจ็คใดๆ เพื่อดูรายชื่อเมธอดทั้งหมดที่สามารถใช้ได้บนออบเจ็ค ดังตัวอย่างต่อไปนี้
p 1.methods
จากตัวอย่าง เป็นการแสดงรายชื่อของเมธอดทั้งหมดที่สามารถใช้ได้กับข้อมูลประเภท Integer
อีกสิ่งหนึ่งที่น่าสนใจในภาษา Ruby คือการใช้งานตัวดำเนินการที่คุณอาจจะคุ้นเคยในภาษาอื่นๆ มาดูตัวอย่างต่อไปนี้
p 1 + 2 # 3
p 4 * 5 # 20
p 8 < 15 # true
ในตัวอย่าง เราได้ทำการบวกเลขด้วยตัวดำเนินการ +
และคูณตัวเลขด้วยตัวดำเนินการ *
และเปรียบเทียบว่าค่าทางซ้ายน้อยกว่าค่าทางขวาหรือไม่ด้วยตัวดำเนินการ <
แต่สำหรับในภาษา Ruby แล้วนั้น คุณเพิ่งจะเรียกใช้เมธอดจากออบเจ็คเหล่านั้น
p 1.+(2) # 3
p 4.*(5) # 20
p 8.<(10) # true
จากในตัวอย่างด้านบน นั่นแสดงให้เห็นว่าจริงๆ แล้วตัวดำเนินการทั้งหมดในภาษา Ruby นั้นเป็นเพียงเมธอดของออบเจ็ค ซึ่งคำสั่ง 1 + 2
และ 1.+(2) นั้นเป็นคำสั่งเดียวกัน มันคือการเรียกใช้เมธอด +
ของออบเจ็ค 1
โดยมี 2
เป็นอาร์กิวเมนต์ของเมธอด
ในภาษา Ruby นั้นคุณสามารถละเว้นวงเล็บในการเรียกใช้งานเมธอดได้ และสำหรับเมธอดที่มีชื่อเป็นสัญลักษณ์อย่างเช่น +
คุณสามารถละเว้นจุดหน้าเมธอดได้ จากที่โดยทั่วไปจะต้องเรียกใช้เมธอดในรูปแบบ: object.method(value)
puts 1
puts(1)
puts "Ruby", "PHP", "Python"
puts("Ruby", "PHP", "Python")
"marcuscode".upcase
"marcuscode".upcase()
ในตัวอย่าง เป็นการเรียกใช้งานเมธอดในภาษา Ruby ซึ่งคุณสามารถละเว้นวงเล็บได้โดยการใช้ช่องว่างคั่นระหว่างชื่อและอาร์กิวเมนต์ของเมธอด และสำหรับเมธอดที่ไม่มีพารามิเตอร์อย่างเช่นเมธอด upcase
คุณสามารถเรียกชื่อเมธอดได้โดยไม่ต้องมีวงเล็บ
และเนื่องจากตัวดำเนินการของ Ruby นั้นเป็นเมธอด ดังนั้นเราสามารถกำหนดการทำงานเมธอดของคลาสใหม่ได้ การกระทำนี้เรียกว่า method overriding ซึ่งเป็นคุณสมบัติหนึ่งในการเขียนโปรแกรมเชิงวัตถุ และในบางภาษานั้นเป็นที่รู้จักกันในชื่อว่า operator overloading
class Integer
def +(b)
self * b
end
end
p 2 + 3
p 2.+(3)
ในตัวอย่างด้านบน เราได้เปลี่ยนพฤติกรรมการทำงานของเมธอด +
ในคลาส Integer
ใหม่ โดยเปลี่ยนจากการบวกเป็นการคูณแทน
6
6
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม ในตอนนี้หลังจากที่เราทำการบวกเลขด้วยตัวดำเนินการ +
บนออบเจ็คของ Integer
ผลลัพธ์ที่ได้จะเป็นผลจากการคูณแทน
อย่างไรก็ตาม คุณไม่ควรทำเช่นนี้กับคลาสหลักของภาษา Ruby ที่เราทำให้คุณดูเพื่อให้คุณเข้าใจว่าตัวดำเนินการในภาษา Ruby นั้นก็เป็นเพียงเมธอด แต่เพื่อให้เข้าใจง่าย สำหรับเนื้อหาในบทเรียนหลังจากนี้ เราจะเรียกมันว่าตัวดำเนินการเหมือนในภาษาอื่นๆ
การสร้างออบเจ็ค
ในตัวอย่างก่อนหน้า เป็นการสร้างออบเจ็คแบบโดยปริยาย (implicit) โดยการกำหนดค่าด้วย Literal ให้กับตัวแปรโดยตรง ซึ่งภาษา Ruby จะแปลงข้อมูลเหล่านั้นเป็นออบเจ็คให้อัตโนมัติเบื้องหลัง นี่เป็นตัวอย่างการสร้างออบเจ็คแบบโดยปริยายหรือกำหนดค่าด้วย Literal
num = 5
lang = "Ruby"
ในทางกลับกัน เราอาจจะสร้างออบเจ็คแบบชัดเจน (explicit) เนื่องจากเรารู้ว่าทุกอย่างในภาษา Ruby นั้นเป็นออบเจ็ค และออบเจ็คนั้นถูกสร้างมากจากคลาส ดังนั้นเราจะใช้คลาสเพื่อสร้างออบเจ็ค
name = String.new "Mateo"
number = Array.new
number.push(1, 2, 3)
puts name
puts number
puts name.class
puts number.class
ในตัวอย่าง เป็นการสร้างออบเจ็คด้วยเมธอด new
ซึ่งเป็นเมธอดของคลาส String
และ Array
แต่สำหรับคลาสบางประเภทอย่างเช่น Integer
Float
หรือ Symbol
คุณไม่สามารถใช้เมธอดดังกล่าวได้ สิ่งที่คุณสามารถทำได้ก็คือการสร้างออบเจ็คด้วย Literal นั่นเอง
Mateo
1
2
3
String
Array
นี่เป็นผลลัพธ์การทำงานของโปรแกรมที่แสดงการสร้างออบเจ็คด้วยคลาส เราได้แสดงค่าของออบเจ็ค และคลาสของมัน
ในตัวอย่างก่อนหน้า ทั้งคลาส String
และ Array
นั้นเป็นคลาสที่มากับภาษา Ruby ที่เราสามารถนำมาใช้ได้เลย อย่างไรตาม คุณสามารถสร้างคลาสขึ้นมาเอง และนำมันมาสร้างออบเจ็คได้ มาดูตัวอย่างกัน
class Being
end
b = Being.new
puts b # <Being:0x0000000004ad2588>
puts b.object_id # 40013840
ในตัวอย่างเราสร้างคลาสที่ชื่อว่า Being
นี่เป็นคลาสที่เรียบง่ายที่สุดและไม่มีการกำหนดอะไรเลย แต่อย่างไรก็ตาม คลาสที่เราสร้างนั้นจะถูกสืบทอดมาจากคลาส Object
อัตโนมัติ และเมื่อเราแสดงค่าของออบเจ็คดังกล่าวด้วยเมธอด puts
จะพบว่ามันมีข้อมูลบางอย่างที่ใช้อธิบายตัวมัน
มาดูตัวอย่างเพิ่มเติมสำหรับการสร้างคลาสในภาษา Ruby
class Book
def initialize(name, author, year)
@name = name
@author = author
@year = year
end
def info
puts "#{@name} by #{@author}, published in #{@year}"
end
end
b1 = Book.new('C Programming', 'Dennis Ritchie', 1972)
b2 = Book.new('Python Programming', 'Guido van Rossum', 1990)
b3 = Book.new('Ruby Programming', 'Yukihiro Matsumoto', 1995)
puts "List of books"
puts b1.info
puts b2.info
puts b3.info
ในตัวอย่าง เราได้สร้างคลาสที่มีชื่อว่า Book
ภายในคลาสนั้นมีเมธอดสองเมธอด เมธอดแรกคือเมธอด initialize
เมธอดทำงานเป็นคอนสตรัคเตอร์ (construct) ที่จะถูกเรียกใช้เมื่อออบเจ็คถูกสร้าง โดยจะมีการรับพารามิเตอร์ที่ส่งเข้ามา
def initialize(name, author, year)
@name = name
@author = author
@year = year
end
พารามิเตอร์ที่ส่งเข้ามายังเมธอดนั้นได้ถูกนำไปสร้างเป็นตัวแปร instance ของคลาส นั่นหมายความว่าทุกออบเจ็คที่ถูกสร้างจากคลาสนี้จะมี ชื่อหนังสือ ชื่อผู้เขียน และปีที่เผยแพร่เป็นของตัวมันเอง
def info
"#{@name} by #{@author}, published in #{@year}"
end
เราได้สร้างเมธอด info
สำหรับแสดงรายละเอียดของหนังสือแต่ละเล่ม ซึ่งประกอบไปด้วยชื่อหนังสือ ชื่อผู้เขียน และปีที่หนังสือถูกเผยแพร่
List of books
C Programming by Dennis Ritchie, published in 1972
Python Programming by Guido van Rossum, published in 1990
Ruby Programming by Yukihiro Matsumoto, published in 1995
และนี่เป็นผลลัพธ์ของการทำงานของโปรแกรม ซึ่งเป็นตัวอย่างสำหรับการสร้างคลาสและออบเจ็คที่นำไปใช้งานจริงได้ ในภาษา Ruby
Ruby object hierarchy
ออบเจ็คทั้งหมดในภาษา Ruby นั้นมีรากฐานหรือถูกสืบทอดมาจากคลาส Object
ซึ่งการสืบทอดนั้นเป็นคุณสมบัติของการเขียนโปรแกรมเชิงวัตถุ โดยที่คลาสหลัก (base class) สามารถสืบทอดคุณสมบัติต่างๆ ของมันไปยังคลาสลูก (delivered class)ได้
puts 1.inspect
puts 5.4.inspect
puts "marcuscode".inspect
puts 1.class
puts 5.4.class
puts "marcuscode".class
ในตัวอย่าง จะเห็นว่าคุณสามารถเรียกใช้งานเมธอด inspect
และเมธอด class
ที่เราได้สร้างขึ้นได้ ซึ่งความจริงแล้วเมธอดเหล่านี้ไม่ได้ถูกกำหนดในคลาส Integer
, Float
หรือ String
แต่มันเป็นเมธอดจากคลาส Object
ที่ได้รับการสืบทอดมานั่นเอง
1
5.4
"marcuscode"
Integer
Float
String
นี่เป็นผลลัพธ์การทำงานของโปรแกรม เราได้แสดงข้อมูลของออบเจ็คแต่ละประเภทด้วยเมธอด inspect
และแสดงคลาสของออบเจ็คเหล่านี้
มาดูตัวอย่างเพิ่มเติมเกี่ยวกับการสืบทอดคลาส เพื่อแสดงให้เห็นว่าคลาสที่เราสร้างขึ้นมาเองก็ถูกสืบทอดมาจากคลาส Object
อัตโนมัติด้วยเช่นกัน
class Point
attr_accessor :x, :y
def initialize(x, y)
@x = x
@y = y
end
def self.distance(a, b)
Math.sqrt((b.x - a.x) ** 2 + (b.y - b.x) ** 2)
end
end
p1 = Point.new(1, 3)
p2 = Point.new(5, 8)
puts p1.inspect
puts p2.inspect
puts Point.distance(p1, p2)
puts p1.instance_of? Point
puts p1.kind_of? Object
ในตัวอย่าง เราได้สร้างคลาส Point
เพื่อเก็บพิกัดบนระนาบสองมิติ ภายในคลาสนั้นมีคลาสเมธอด distance
ใช้สำหรับคำนวณหาระยะห่างระหว่างจุดสองจุด
puts p1.inspect
puts p2.inspect
puts Point2D.distance(p1, p2)
เราได้เรียกใช้เมธอด inspect
บนออบเจ็ค p1
และ p2
ซึ่งเป็นเมธอดที่สืบทอดมาจากคลาส Object
และแสดงระยะห่างระหว่างพิกัด 1, 3
และ 5, 8
บนระนาบสองมิติ
puts p1.instance_of? Point
puts p1.kind_of? Object
ต่อมาเป็นการเรียกใช้เมธอด instance_of?
เพื่อตรวจสอบว่าออบเจ็ค p1
นั้นถูกสร้างมาจากคลาส Point
หรือไม่ และเมธอด kind_of?
เพื่อตรวจสอบว่าคลาสของออบเจ็คนั้นได้สืบทอดมาจากคลาส Object
หรือไม่
#<Point2D:0x0000000004b6fbf8 @x=1, @y=3>
#<Point2D:0x0000000004b6fba8 @x=5, @y=8>
5.0
true
true
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม ซึ่งจะแสดงรายละเอียดของแต่ละออบเจ็ค และระยะห่างระหว่างจุดสองจุด สังเกตุในบรรทัดสุดท้ายผลลัพธ์ที่ได้นั้นเป็น true
นั่นแสดงว่าคลาส Point
ได้ถูกสืบทอดมาจากคลาส Object
Ruby top-level
Ruby มีออบเจ็คหลักที่สามารถอ้างถึงได้คือ Ruby top-level มันเป็นส่วนพื้นที่การทำงานหลักของโปรแกรมที่อยู่นอกสุดและมีชื่อเรียกว่า main
มันคือออบเจ็ค instance ที่สร้างมาจากคลาส Object
ดังนั้นโค้ดที่เราเขียนขึ้นทั้งหมดไม่ว่าจะเป็นคลาส เมธอด และโมดูล จะอยู่ภายใน top-level จะอยู่ใน top-level ซึ่งเป็นสภาพแวดล้อมการทำงานหลักของ Ruby
a = 2
b = 5
puts local_variables
Kernel.puts self
puts self.class
ในตัวอย่างนั้นอธิบายการทำงานของ Ruby top-level
a = 2
b = 5
ในตอนแรก เราได้ประกาศตัวแปรสองตัวสำหรับเก็บค่าตัวเลข ซึ่งตัวแปรเหล่านี้มีขอบเขตอยู่ภายใน toplevel
puts local_variables
ต่อมาเราแสดงรายการของตัวแปร local ทั้งหมดออกมาด้วยเมธอด local_variables
ซึ่งเป็นเมธอดที่อยู่ภายในโมดูล Kernel
ที่สามารถใช้งานได้กับออบเจ็คทุกออบเจ็ค รวมทั้ง top-level เอง
Kernel.puts self
ตัวแปร self
นั้นเป็นตัวแปรสำหรับอ้างถึงออบเจ็คปัจจุบัน ในที่นี้มันหมายถึง top-level เราแสดงค่ามันออกมาด้วยเมธอด puts
จะเห็นว่า "name"
นั้นเป็นชื่อของมัน
puts self.class
ต่อมาเราใช้เมธอด class
เพื่อดูว่าคลาสของ top-level คืออะไร
ในตัวอย่าง จะเห็นว่าเราเรียกใช้เมธอด puts
โดยไม่มี Kernel.
นั่นเป็นเพราะว่าโมดูลดังกล่าวถูกนำเข้ากับคลาส Object
อยู่แล้ว ซึ่งเป็นสภาพแวดล้อมการทำงานปัจจุบันของโปรแกรม ทำให้เราสามารถเรียกชื่อของเมธอดได้ทันที
a
b
main
Object
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม ตัวแปร a
และ b
นั้นเป็นตัวแปร local ในขอบเขตของ top-level ส่วน main
นั้นเป็นชื่อถูกกำหนดให้กับ top-level ในสภาพแวดล้อมการทำงานของมัน และสุดท้าย Object
นั้นเป็นประเภทของ top-level
ต่อไปมาดูตัวอย่างเพิ่มเติมเกี่ยวกับ Ruby top-level
@name = "Mateo"
@height = 5.9
def info
"#{@name} is #{@height} feets tall"
end
puts self.instance_variables
puts self.private_methods.include? :info
puts info
ในตัวอย่าง นั้นเป็นการประกาศตัวแปร instance และเมธอดที่อยู่ภายในขอบเขตของ top-level
@name = "Mateo"
@height = 5.9
เราได้ประกาศสองตัวแปร instance ซึ่งเป็นตัวแปรของ top-level และ instance เมธอดสำหรับแสดงค่าตัวแปรดังกล่าว
puts self.instance_variables
เราได้แสดงรายการของตัวแปร instance ภายใน top-level ด้วยเมธอด instance_variables
puts self.private_methods.include? :info
เมธอด private_methods
ส่งค่ากลับเป็นอาเรย์ของ symbol ของ private เมธอดทั้งหมดใน top-level เนื่องจากคลาสออบเจ็คนั้นมีเมธอดเป็นจำนวนมาก เราจึงใช้เมธอด include?
ของอาเรย์เพื่อตรวจสอบว่ามีเมธอด info
อยู่หรือไม่
puts info
เราเรียกใช้เมธอด info
เพื่อแสดงชื่อและความสูงที่ได้เก็บไว้ในตัวแปร instance
@name
@height
true
Mateo is 5.9 feets tall
นี่เป็นผลลัพธ์การทำงานของโปรแกรม เราได้แสดงตัวแปร instance ทั้งหมดออกมา และแสดงให้เห็นว่าเมธอด info
นั้นเป็นเมธอดของ top-level ออบเจ็ค และสุดท้ายแสดงรายละเอียดด้วยเมธอดดังกล่าว
ในบทนี้ คุณได้ทำความเข้าในเกี่ยวกับออบเจ็คในภาษา Ruby อย่างไรก็ตาม คุณจะได้เรียนเกี่ยวกับคลาส ออบเจ็ค และคุณสมบัติอื่นๆ ของมันอีกครั้งในบทการเขียนโปรแกรมเชิงวัตถุในภาษา Ruby