Preface
在 Ruby 中要定義類別非常的簡單,例如你可以定義一個帳戶(Account)類別:
- # encoding: utf-8
- class Account; end
- acct = Account.new
- def acct.initialize(number, name, balance)
- @number = number
- @name = name
- @balance = balance
- end
- def acct.number
- @number
- end
- def acct.name
- @name
- end
- def acct.balance
- @balance
- end
- def acct.deposit(money)
- if money <= 0
- raise ArgumentError, "必須是正數"
- end
- @balance += money
- end
- def acct.withdraw(money)
- if money > @balance
- raise RuntimeError, "餘額不足"
- end
- @balance -= money
- end
- acct.initialize("123-456-789", "Justin", 0)
- puts acct.number # 123-456-789
- puts acct.name # Justin
- acct.deposit(100)
- puts acct.balance # 100
- acct.withdraw(50)
- puts acct.balance # 50
定義類別
以 @ 開頭的變數稱為 實例變數(Instance variable),顧名思義,為個別物件擁有的變數,實例變數無法直接由外部存取,必須自行定義方法,外部才可以取得實例變數的值,這也就是為何,上例中要再特別定義 name、number、balance 等方法的原因。上面這個例子定義了類別,但沒有封裝的概念,deposit、withdraw 等方法,都僅屬於 acct 參考的物件擁有,可以將物件建立後的初始化動作,以及會用到的相關操作定義在類別之中。來看看下面這個例子:
- # encoding: utf-8
- class Account
- def initialize(number, name, balance)
- @number = number
- @name = name
- @balance = balance
- end
- def number
- @number
- end
- def name
- @name
- end
- def name=(value)
- @name = value
- end
- def balance
- @balance
- end
- def deposit(money)
- if money <= 0
- raise ArgumentError, "必須是正數"
- end
- @balance += money
- end
- def withdraw(money)
- if money > @balance
- raise RuntimeError, "餘額不足"
- end
- @balance -= money
- end
- end
- acct = Account.new("123-456-789", "Justin", 0)
- puts acct.number # 123-456-789
- puts acct.name # Justin
- acct.deposit(100)
- puts acct.balance # 100
- acct.withdraw(50)
- puts acct.balance # 50
- acct.name = "Caterpillar"
- puts acct.name # caterpillar
上例中,建立物件並初始化之後,為了可以取得與設定實例變數,必須自行定義方法。實際上,可以使用 attr_reader 方法定義取值方法,attr_writer 定義設值方法,或者使用 attr_accessor 同時定義取值與設值方法,attr_reader、attr_writer 與 attr_accessor 接受的是 符號型態 實例。例如:
- # encoding: Big5
- class Account
- attr_reader :number, :balance
- attr_accessor :name
- def initialize(number, name, balance)
- @number = number
- @name = name
- @balance = balance
- end
- def deposit(money)
- if money <= 0
- raise ArgumentError, "必須是正數"
- end
- @balance += money
- end
- def withdraw(money)
- if money > @balance
- raise RuntimeError, "餘額不足"
- end
- @balance -= money
- end
- end
- acct = Account.new("123-456-789", "Justin", 0)
- puts acct.number # 123-456-789
- puts acct.name # Justin
- acct.deposit(100)
- puts acct.balance # 100
- acct.withdraw(50)
- puts acct.balance # 50
- acct.name = "Caterpillar"
- puts acct.name
Array 原本沒有 ^ 方法,在上例中開啟 Array 類別定義了 ^ 方法,使 Array 實例都可以呼叫 ^ 方法。可以開啟類別定義新方法,既有的類別已定義的方法,也可以移除,只要使用remove_method 方法(若必要,也可以移除實例變數,可搜尋 remove_instance_variable 方法的使用)。例如:
在 Ruby,定義於類別中的方法,預設會是公開(public),可以使用 public、private或protected 方法定義指定的方法為公開、私有或受保護,公開的方法可以直接指定物件接收者(包括self)直接呼叫,私有方法則只能在有繼承關係的類別體系中不透過 self 呼叫,受保護方法則可以在有繼承關係的類別體系中指定物件接收者(包括self)呼叫。例如::
initialize方法一定是private。
可以使用 instance_of? 方法測試物件是否為某個類別的實例,如果要知道是否為某個繼承體系的實例,則可以使用 is_a? 或 === 方法。例如:
之後會學到繼承,在 Ruby 中,所有的類別都是 Object 的子類別,因此所有物件都是一種 Object。
Supplement
* Ruby 手冊 - 類別
* Ruby tutorialspoint - Ruby Classes and Objects
沒有留言:
張貼留言