Ruby:Instance Variables

From Blognone

Jump to: navigation, search

หลังจากที่เราได้ Class BankAccount จากบทที่แล้ว เรามาลองเรียก balance ออกมาจาก method Bank account ดู

my_account = BankAccount.new('Russ')
        puts(my_account.balance)

เราจะเจอ error ว่า

account.rb:8: undefined method 'balance' ... (NoMethodError)

แปลว่าแทนที่มันจะไปหาตัวแปล balance มันกลับไปตามหา method balance แทน ... ไม่ต้องทดลอง my_account.@balance นะครับ ตัวแปลใน rails ไม่สามารถเรียกใช้โดยตรงได้จากนอก object

แล้วถ้าต้องการเรียกใช้ตัวแปลจากนอก object สิ่งที่ต้องทำคือกำหนด accessor method ให้กับตัวแปล

def balance
	  @balance
	end

สิ่งสุดท้ายที่ method balance ทำคือค่า @balance ดังนั้นสิ่งที่ return ออกมาคือ @balance หากทดลองเรียบกใช้แบบเดิม

my_account = BankAccount.new('Russ')
        puts(my_account.balance)

Ruby จะแสดงค่า @balance ออกมาอย่างถูกต้อง ... แล้วถ้าต้องการกำหนดค่าให้กับ @balance ล่ะ?

def set_balance(new_balance)
	  @balance = new_balance
	end

set_balance สามารถทำงานได้ดีเยี่ยมเหมือน method balance

my_account.set_balance(100)

ปัญหาคือมันไม่สวยและดูไม่เป็นธรรมชาติ มันจะดีกว่านี้ถ้าเป็น

my_account.balance = 100

ทำอย่างไรเราถึงจะสามารถสร้าง method ให้เป็นธรรมชาติและ ได้คุณสมบัติ encapsulation ไปพร้อมๆ กัน

def balance=(new_balance)
	  @balance = new_balance
	end

เปลี่ยนชื่อ method โดยใส่ "=" ลงไป

my_account.balance=(100)

หรือ

my_account.balance= 100

หรือ

my_account.balance = 100

ถ้าไม่ต้องการจ้างคนมาเขียน set, get จำนวนมาก Ruby มีคำสั่ง attr_accessor ซึ่งจะช่วยสร้าง set และ get ในแบบที่เราพูดถึงข้างต้น

attr_accessor :balance

วิธีนี้ช่วยลด method ได้หลายบรรทัดทีเดียว หรือจะใช้ทีละหลายๆ ตัวแปลก็ได้

attr_accessor :balance, :grace, :agility

และในกรณีที่ต้องการให้อ่านอย่างเดียวให้ใช้ attr_reader

attr_reader :name

ทีนี้ลองเดาว่า attr_writer ใช้ทำอะไร