คลาสและออบเจ็ค ในภาษา Ruby

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับคลาสในภาษา Ruby เราจะพูดเกี่ยวกับการสร้างคลาสและการนำคลาสไปสร้างออบเจ็ค และเราจะอธิบายเกี่ยวกับแนวคิดการเขียนโปรแกรมเชิงวัตถุ (OOP) ซึ่งเป็นรูปแบบของการเขียนโปรแกรมโดยการมองทุกอย่างเป็นวัตถุ ซึ่งจะมีข้อมูลและการกระทำในตัวมันเอง ก่อนเริ่ม มาดูกันก่อนว่าคลาสคืออะไร

คลาสคืออะไร

คลาส (Class) นั้นเป็นแม่แบบที่ใช้สำหรับการสร้างออบเจ็ค ออบเจ็คสามารถประกอบไปด้วยแอททริบิวต์ (Attribute) ซึ่งเป็นข้อมูลที่ใช้อธิบายออบเจ็คนั้นๆ และเมธอดซึ่งเป็นฟังก์ชันการทำงานของออบเจ็ค ซึ่งทั้งสองอย่างนี้นั้นจะถูกกำหนดไว้ในคลาส เมื่อเราสร้างคลาสขึ้นมาแล้ว เราสามารถนำคลาสดังกล่าวไปสร้างเป็นออบเจ็คได้ หรือกล่าวอีกนัยหนึ่ง คลาสเป็นประเภทข้อมูลของออบเจ็ค

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

การสร้างคลาสในภาษา Ruby

อย่างไรก็ตาม เราจะเริ่มต้นกับการสร้างคลาสก่อน ซึ่งเป็นจุดเริ่มต้นของการเขียนโปรแกรมเชิงวัตถุ นี่เป็นรูปแบบการประกาศคลาสในภาษา Ruby

class Name
    # Class definition
end

จากรูปแบบการประกาศ เราใช้คำสั่ง class สำหรับเริ่มต้นการประกาศคลาส และ Name นั้นเป็นชื่อของคลาส ชื่อของคลาสนั้นต้องเริ่มต้นด้วยตัวพิมพ์ใหญ่และคั่นแต่ละคำด้วยรูปแบบ Camel case และสิ้นสุดการประกาศคลาสด้วยคำสั่ง end ภายในบล็อคของคลาส จะเป็นการกำหนดแอททริบิวต์และเมธอดของคลาส

ต่อไปเราจะสร้างคลาสของรูปสี่เหลี่ยมและที่สามารถกำหนดความยาวและความสูงได้ และมีเมธอดสำหรับหาพื้นที่ของรูปสี่เหลียมดังกล่าว นี่เป็นตัวอย่างคลาสแรกของเรา

rectangle.rb
class Rectangle

    attr_accessor(:width, :height)

    def area
        return @width * @height
    end

end

# Creating objects
rect = Rectangle.new
rect.width = 2
rect.height = 4

puts "Width: #{rect.width}"
puts "Height: #{rect.height}"
puts "Calculate area: #{rect.area}"

ในตัวอย่าง เราได้สร้างคลาสที่มีชื่อว่า Rectangle ซึ่งคลาสมีนี้มีแอททริบิวต์สองตัวคือ width และ height สำหรับเก็บความยาวและความสูงของออบเจ็คสี่เหลี่ยม และเมธอด area สำหรับคำนวณหาพื้นที่ของรูปสี่เหลี่ยม

attr_accessor(:width, :height)

คำสั่งแรกที่คุณเห็นภายในคลาสก็คือเราได้เรียกใช้เมธอด attr_accessor เมธอดนี้ใช้สำหรับกำหนดแอททริบิวต์ให้กับคลาส โดยการระบุชื่อแอททริบิวต์เป็น Symbol ที่เราต้องการให้คลาสมี เราได้ระบุ Symbol :width และ :height และเมธอด attr_accessor จะสร้างสองเมธอดสำหรับกำหนดค่าและรับค่าสำหรับแต่ละแอททริบิวต์

def width=(value)
    @width = value
end

def width
    return @width
end

def height=(value)
    @height= value
end

def height
    return @height
end

นี่เป็นสิ่งที่เราได้รับจากการทำงานเบื้องหลังของเมธอด attr_accessor มันได้สร้างเมธอดสำหรับกำหนดค่าและอ่านค่าของแอททริบิวต์ให้กับเรา ทำให้เราสามารถเข้าถึงแอททริบิวต์จากภายนอกคลาสได้

def area
    return @width * @height
end

ต่อมาเรามีเมธอด area เมธอดนี้ใช้สำหรับคำนวณหาพื้นที่ของรูปสี่เหลี่ยมจากความกว้างและความยาวที่ถูกเก็บในแอททริบิวต์ @width และ @height และอย่างที่คุณเห็น เมื่อเราเข้าถึงแอททริบิวต์ภายในคลาส มันจะต้องขึ้นต้นด้วยเครื่องหมาย @ เสมอ

rect = Rectangle.new

หลังจากที่เราสร้างคลาสเสร็จแล้ว เราสามารถนำคลาสไปสร้างออบเจ็คได้ ในตัวอย่างเราได้นำคลาสมาสร้างออบเจ็คโดยการเรียกใช้งานเมธอด new บนคลาส Rectangle เมธอดนี้เป็นเมธอดที่มีอยู่ในทุกคลาสในภาษา Ruby มันใช้สร้างออบเจ็คของคลาสดังกล่าว และเรากำหนดออบเจ็คไว้ในตัวแปร rect

rect.width = 2
rect.height = 4

หลังจากที่เราสร้างออบเจ็คแล้ว เราได้กำหนดค่าความยาวและความสูงให้กับออบเจ็คสี่เหลี่ยมของเรา ในทางทฤษฏีแล้ว เราได้เรียกใช้งานเมธอด width= และ height= สำหรับกำหนดค่าให้กับแอททริบิวต์ ซึ่งเมธอดเหล่านี้ถูกสร้างโดยเมธอด attr_accessor ที่เราได้บอกไปก่อนหน้า

puts "Width: #{rect.width}"
puts "Height: #{rect.height}"
puts "Calculate area: #{rect.area}"

หลังจากนั้นเราเรียกใช้งานเมธอด width และเมธอด height เพื่อดูความยาวและความสูงที่เราเพิ่งได้กำหนดไป และเรียกใช้เมธอด area เพื่อคำนวณหาพื้นที่ของรูปสี่เหลี่ยม

Width: 2
Height: 4
Calculate area: 8

นี่เป็นผลลัพธ์การทำงานของโปรแกรม เราได้สร้างคลาสของรูปสี่เหลี่ยมที่เก็บความยาวและความสูง และนำคลาสไปสร้างเป็นออบเจ็คเพื่อใช้งาน

การนำคลาสไปสร้างออบเจ็ค

ในการสร้างคลาสนั้น วัตถุประสงค์ของมันก็คือการนำคลาสไปสร้างเป็นออบเจ็ค ในตัวอย่างก่อนหน้า เราได้สร้างเพียงหนึ่งออบเจ็คสำหรับคลาส Rectangle อย่างไรก็ตาม เราสามารถนำคลาสไปสร้างออบเจ็คกี่ออบเจ็คก็ได้ ซึ่งนี่เองเป็นแนวคิดของการนำโค้ดกลับมาใช้ใหม่ (Code reuse) นี่เป็นตัวอย่าง

creating_objects.rb
class Rectangle

    attr_accessor(:width, :height)

    def set_size(w, h)
        @width = w
        @height = h
    end

    def show_size
        puts "Width: #{@width}, Height: #{@height}"
    end

    def area
        return @width * @height
    end

end

# Creaing objects
rect = Rectangle.new
rect.set_size(2, 4)

rect2 = Rectangle.new
rect2.set_size(3, 5)

puts "Rect 1"
rect.show_size
puts "Area: #{rect.area}"

puts "Rect 2"
rect2.show_size
puts "Area: #{rect2.area}"

ในตัวอย่าง เราได้ใช้คลาส Rectangle จากในตัวอย่างก่อนหน้า แต่สำหรับคลาสในตัวอย่างนี้เราได้เพิ่มเมธอด set_size และเมธอด show_size เข้ามา

def set_size(w, h)
    @width = w
    @height = h
end

เมธอด set_size นั้นเป็นเมธอดที่ใช้สำหรับกำหนดความยาวและความกว้างให้กับออบเจ็ค ซึ่งเมธอดนี้มีอาร์กิวเมนต์สองตัวที่รับเข้ามาคือ w และ h สำหรับกำหนดความยาวและความสูงให้กับแอททริบิวต์ @width และ @height เราสร้างเมธอดนี้ขึ้นมาเนื่องจากเราไม่ต้องการกำหนดแอททริบิวต์ทีละค่าเหมือนในตัวอย่างก่อนหน้า

def show_size
    puts "Width: #{@width}, Height: #{@height}"
end

ต่อมาเป็นเมธอด show_size เมธอดนี้ใช้สำหรับแสดงขนาดของออบเจ็ค ซึ่งเป็นความยาวและความสูงนั่นเอง โดยการใช้เมธอดนี้ทำให้เราไม่จำเป็นต้องเขียนโค้ดการแสดงผลเป็นจำนวนมากที่ภายนอกคลาสเหมือนในตัวอย่างก่อนหน้า

rect = Rectangle.new
rect.set_size(2, 4)

rect2 = Rectangle.new
rect2.set_size(3, 5)

หลังจากนั้นเราได้นำคลาสมาสร้างออบเจ็ค ในคราวนี้เราได้สร้างสองออบเจ็คได้แก่ rect และ rect2 ซึ่งเมื่อทั้งสองออบเจ็คถูกสร้าง มันจะมีแอททริบิวต์และเมธอดเป็นของมันเอง เราได้เรียกเมธอด set_size สำหรับกำหนดขนาดให้แต่ละออบเจ็ค

puts "Rect 1"
rect.show_size
puts "Area: #{rect.area}"

หลังจากนั้นเราแสดงรายละเอียดเกี่ยวกับออบเจ็คด้วยเมธอด show_size และอย่างที่คุณเห็น เมื่อเราเรียกใช้เมธอด การแสดงผลจะขึ้นอยู่กับแอททริบิวต์ของออบเจ็คนั้นๆ นี่แสดงให้เห็นว่าออบเจ็คที่สร้างจากคลาสเดียวกัน แต่มันมีแอททริบิวต์และเมธอดเป็นของมันเอง นี่ทำให้เราสามารถใช้โค้ดภายในคลาสกับออบเจ็คเป็นจำนวนเท่าไหร่ก็ได้

Rect 1
Width: 2, Height: 4
Area: 8
Rect 2
Width: 3, Height: 5
Area: 15

นี่เป็นผลลัพธ์การทำงานของโปรแกรมจากการรันตัวอย่างสำหรับการนำคลาสมาสร้างเป็นออบเจ็คในภาษา Ruby

คอนสตรัคเตอร์ของคลาส

คอนสตรัคเตอร์นั้นเป็นเมธอดพิเศษที่ใช้สำหรับกำหนดเพื่อให้ทำงานบางอย่างในตอนที่ออบเจ็คถูกสร้าง ยกตัวอย่าง เช่น การกำหนดค่าเริ่มต้นให้กับออบเจ็ค โดยในภาษา Ruby นั้นคอนสตรัคเตอร์เมธอดต้องมีชื่อว่า initialize เสมอ มันสามารถรับอาร์กิวเมนต์ได้เหมือนกับเมธอดปกติ โดยทั่วไปแล้วเมธอดนี้จะถูกเรียกใช้งานเมื่อเราสร้างออบเจ็คด้วยเมธอด new ของคลาสใดๆ

ต่อไปเป็นตัวอย่างสำหรับการประกาศคอนสตรัคเตอร์เมธอดให้กับคลาส เราจะสร้างคลาส Book ซึ่งเป็นคลาสของหนังสือ

book.rb
class Book

    attr_accessor(:name, :author, :year)

    def initialize(name, author, year)
        @name = name
        @author = author
        @year = year
    end

    def info
        puts "#{@name} by #{@author}, published in #{@year}"
    end

    def year_passed
        return Time.now.year - @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"
b1.info
b2.info
b3.info

puts "\nHow long Ruby programming book published?"
puts "Answer: #{b3.year_passed} years ago"

ในตัวอย่าง เราได้สร้างคลาสที่มีชื่อว่า Book คลาสนี้ประกอบไปด้วยแอททริบิวต์สามตัวคือ name สำหรับเก็บชื่อของหนังสือ author สำหรับเก็บชื่อของผู้เขียนหนังสือ และ year สำหรับเก็บปีที่หนังสือถูกเผยแพร่ เราได้ระบุแอททริบิวต์เหล่านี้ด้วยเมธอด attr_accessor

def initialize(name, author, year)
    @name = name
    @author = author
    @year = year
end

ภายในเมธอด initialize ซึ่งเป็นคอนสตรัคเตอร์ของคลาสของเรา นั้นรับสามอาร์กิวเมนต์และนำอาร์กิวเมนต์เหล่านั้นกำหนดเป็นชื่อของหนังสือ ชื่อผู้เขียน และปีที่เผยแพร่ตามลำดับ หรือจะกล่าวอีกนัยหนึ่งก็คือเราใช้เมธอดนี้สำหรับกำหนดค่าเริ่มต้นให้กับออบเจ็ค ซึ่งเมธอดนี้จะถูกเรียกใช้งานในตอนที่ออบเจ็คถูกสร้าง

def info
    puts "#{@name} by #{@author}, published in #{@year}"
end

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

def year_passed
    return Time.now.year - @year
end

และเมธอดสุดท้าย year_passed เมธอดนี้ใช้สำหรับคำนวณหาว่าหนังสือได้เผยแพร่ไปนานเท่าไหร่แล้ว เราใช้เมธอดนี้ในกรณีที่เราต้องการทราบว่าเวลาผ่านไปนานเท่าไหร่ โดยการนำปีที่เผยแพร่ไปลบออกจากปีปัจจุบัน ซึ่งคำสั่ง Time.now.year นั้นใช้สำหรับรับค่าปีปัจจุบันในคอมพิวเตอร์ของเรา

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)

หลังจากที่เราได้ประกาศคลาสเสร็จเรียบร้อยแล้ว เราได้นำคลาสมาสร้างออบเจ็คสามออบเจ็ค สังเกตว่าในตอนสร้างออบเจ็คเราสามารถกำหนดค่าให้กับออบเจ็คผ่านทางเมธอด new ได้เลย ซึ่งค่าเหล่านี้จะถูกส่งผ่านเข้าไปยังเมธอด initialize ซึ่งเป็นคอนสตรัคเตอร์ของคลาสนั่นเอง

puts "List of books"
b1.info
b2.info
b3.info

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

puts "\nHow long Ruby programming book published?"
puts "Answer: #{b3.year_passed} years ago"

และในสองคำสั่งสุดท้ายนั้นเราต้องการทราบว่าหนังสือภาษา Ruby นั้นถูกเผยแพร่มาแล้วเป็นเวลากี่ปี เราสามารถใช้เมธอด year_passed สำหรับรับค่าเวลาที่ผ่านไปเป็นปีได้

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

How long Ruby programming book published?
Answer: 25 years ago

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

b1 = Book.new
b1.name = 'C Programming'
b1.author = 'Dennis Ritchie'
b1.year = 1972

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

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