ออบเจ็ค ในภาษา 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
"#{@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