程式扎記: [ Ruby Gossip ] Basic : 類別 - 使用繼承

標籤

2014年11月11日 星期二

[ Ruby Gossip ] Basic : 類別 - 使用繼承

Source From Here
你建立了一個銀行帳戶類別:
  1. # encoding: utf-8  
  2. class Account  
  3.     def initialize(id, name)  
  4.         @id = id  
  5.         @name = name  
  6.         @balance = 0  
  7.     end  
  8.       
  9.     def deposit(amt)  
  10.         @balance += amt  
  11.     end  
  12.       
  13.     def withdraw(amt)  
  14.         if amt >= @balance  
  15.             @balance -= amt  
  16.         else  
  17.             raise RuntimeError, "餘額不足"  
  18.         end  
  19.     end  
  20.       
  21.     def to_s  
  22.         "  
  23.         id\t\t#{@id}  
  24.         name\t\t#{@name}  
  25.         balance\t\t#{@balance}  
  26.         "  
  27.     end  
  28. end  
在這個類別中,雖然沒有聲明,但你已經使用了繼承,在 Ruby 中,所有類別都繼承自 Object 類別。上例其實相當於:
  1. class Account < Object  
  2.     ...  
在 Ruby 中繼承的語法,是在類別名稱旁使用 < 表明要繼承的父類別。例如,你為以上的類別建立了一個支票帳戶:
  1. ...  
  2. class CheckingAccount < Account  
  3.     def initialize(id, name)  
  4.         super(id, name) # 呼叫父類別 initialize 方法  
  5.         @overdraftlimit = 30000  
  6.     end  
  7.       
  8.     def withdraw(amt)  
  9.         if amt <= @balance + @overdraftlimit  
  10.             @balance -= amt  
  11.         else  
  12.             raise RuntimeError, "超出信用額度"  
  13.         end  
  14.     end  
  15.       
  16.     def to_s  
  17.         super +  # 呼叫父類別 to_s 方法  
  18.         "Over limit\t#{@overdraftlimit}  
  19.         "  
  20.     end  
  21. end  
在上例中,你繼承了Account 來定義一個 CheckingAccount 子類別。如果在子類別中,需要呼叫父類別的方法,可以使用 super(...) 方法。如果在子類別,沒有定義初始方法,預設就會呼叫父類別初始方法,所有傳給子類別 new 的引數,都會傳給父類別初始方法。

在上例中,你重新定義了 withdraw 與 to_s 方法,在重新定義實例方法時,如果想要呼叫父類別中某個實例方法,也是使用 super。在操作實例方法時,是從子類別開始尋找是否有定義,否則就搜尋父類別中是否有定義方法。所以:
- main.rb
  1. # encoding: utf-8  
  2. require "Account"  
  3. require "CheckingAccount"  
  4.   
  5. acct = CheckingAccount.new("E1234""Justin Lin")  
  6. printf "***Initialize***\n"  
  7. puts acct           # 使用 CheckingAccount 的 to_s 定義  
  8. printf "***Deposit 1000***\n"  
  9. acct.deposit(1000)  # 使用 Account 的 deposit 定義  
  10. puts acct  
  11. printf "***Withdraw 2000***\n"  
  12. acct.withdraw(2000) # 使用 CheckingAccount 的 withdraw 定義  
  13. puts acct  
在 Ruby 中,只能進行單一繼承,也就是一個子類別只能有一個父類別,Ruby 中所有類別都是 Object 的直接或間接子類別。

類別方法屬於類別擁有,基本上沒有繼承問題,不過在子類別中若定義了與父類別同名的類別方法,而又要使用父類別中的類別方法,可以如下:


在 Ruby 中,類別有個 superclass 方法,可取得繼承的父類別:
>> Other.superclass
=> Some
>> Other.superclass.superclass
=> Object

父類別中的實例變數可以直接被子類別取用,private 方法在子類別中也可以不透過 self 直接呼叫,也可以使用 super 呼叫,但子類別不可透過 self 呼叫 private 方法,在子類別中可透過 self 呼叫的父類別方法,必須是 protected 或 public。

Supplement
Ruby 手冊 - 繼承 Inheritance
Stackoverflow - Adding a directory to $LOAD_PATH (Ruby)
I would say go with $:.unshift File.dirname(__FILE__) over the other one, simply because I've seen much more usage of it in code than the $LOAD_PATH one, and it's shorter too...


沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!