iT邦幫忙

DAY 23
1

Ruby女孩:10萬.times { puts "為什麼?" }系列 第 23

Ruby女孩(23):Ruby中的繼承者們!有錢真好(誤)

今天要來看看怎麼建立類別的孩子、孫子、子子孫孫們!實際上先前我們已經有偷偷用過了,不過今天來做個詳細的介紹!

※ 建立子類別

通常我們如果需要建立子類別(subclass),都是為了要**沿用父類別(superclass)的方法**,然後再擴充自己的方法。(你知道的,通常父母都會把自己的全部送給孩子,然後孩子自己再去發展自己的事業XD)

還記得我們寫過...

Fixnum.ancestors
=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]

Fixnum的爸爸是Integer,其他都是Fixnum的祖先,Fixnum有其他祖先所定義的所有方法!

那如果我們要自己寫一個子類別的話該怎麼做呢?很簡單我們只需要一個『<』符號就好了!

class RubyGirl < Girl

end

上面我將RubyGirl定義成是Girl的子類別,所以會有所有Girl的方法!例如:

class Girl
  attr_accessor :talk, :height, :weight
  def talk
    "Hi, nice to meet you!"
  end
end
class RubyGirl < Girl
  attr_accessor :age, :ruby_skill
  def initialize(height=180,weight=40,ruby_skill=60,age=18)
    @height = height
    @weight = weight
    @ruby_skill = ruby_skill
    @age = age
  end
end

annie = RubyGirl.new
=> #<RubyGirl:0x007fa7c3052e78 @height=180, @weight=40, @ruby_skill=60, @age=18>

看到了嗎,我們明明是在Girl這個類別定義身高、體重這兩個方法,而annie是RubyGirl類別的實體物件,但annie初始化時也可以使用Girl中的方法!當然,annie也享有說話這個方法,因為RubyGirl繼承Girl,所以:

annie.talk
=> "Hi, nice to meet you!"

※ 覆寫方法

不過有時候,孩子可能不太喜歡父母的規定,例如annie的talk並不想要這麼死板XD,那RubyGirl這個類別可以做些修改來重新定義父母的行為,例如:

class Girl
  def talk
    "Hi, nice to meet you!"
  end
end
class RubyGirl < Girl
  def talk
    "Hey, folks~~~"
  end
end

annie = RubyGirl.new
=> #<RubyGirl:0x007fde6438f708>

annie.talk
=> "Hey, folks~~~"

書中提到(p.246):『當方法被調用時,會動態查找該方法,所以會發現該方法的定義或是他的新定義。』

有些父母比較彈性,會在自己的方法中挖空,讓子女來定義也是完全可以的噢,以下我們來介紹抽象的類別:

class Girl
  def talk
    "#{greeting} #{who}"
  end
end
#上面這個父類別的talk方法都被挖空了!

#挖空的內容讓下面的子類別來定義!
class RubyGirl < Girl
  def greeting
    "Hey,"
  end
  def who
    "folks~~~"
  end
end

annie = RubyGirl.new
=> #<RubyGirl:0x007f9e6cad13a0>

annie.talk
=> "Hey, folks~~~"

※ 覆寫私用方法

昨天有提到,一個類別的私用方法不能被類別以外的地方使用,但是是可以被子類別調用與覆寫的,我們曾經在Ruby女孩(21)中提到一個叫做super的寫法,當時只有簡單說明,如果我們想要擴充而非完全取代舊有的方法,那我們一定要加上super才行!
super是一種透過鏈結(chaining)的方式來覆寫父類別的方法下面的例子指出,我在建立RubyGirl的實體物件時,初始化的內容包含四個引數,其中兩個來自父類別的相同名稱方法中(height,weight來自Girl的initialize方法),後面兩個則在自己的類別中處理(ruby_skill,age來自RubyGirl自己的initialize方法)。

class Girl
  attr_accessor :height, :weight
  def initialize(height,weight)
    @height = height
    @weight = weight
  end
end
class RubyGirl < Girl
  attr_accessor :age, :ruby_skill
  def initialize(height,weight,ruby_skill=60,age=18)
    super(height,weight)
    @ruby_skill = ruby_skill
    @age = age
  end
end

annie = RubyGirl.new(180,40)
=> #<RubyGirl:0x007fa81b017140 @height=180, @weight=40, @ruby_skill=60, @age=18>

※ 當繼承遇到公用、受保護、私用方法

最後我們來看看繼承與昨天公用、受保護、私用方法之間錯綜複雜的關係為何?

直接來看例子,你就可以知道生在好的人家裡面多重要了(大誤),繼承者完全可以使用老爸的公用、受保護、私用方法

class Father
  def friend
    "Dad have a lot of friends"
  end

  protected

  def money
    "Dad have a lot of money"
  end

  private

  def company
    "Dad have a lot of company"
  end
end

class Son < Father
  def son_friend
    "#{self.class} and #{friend}"
  end
  def son_money
    "#{self.class} and #{money}"
  end
  def son_company
    "#{self.class} and #{company}"
  end
  def son_all
    secret
  end

  private
  def secret
    puts "hey hey A__A i told you a secret: \n #{friend} \n #{money} \n #{company}"
  end
end

dd = Son.new
=> #<Son:0x007faefc920ce0>

#完全可以用老爸的公用方法
dd.son_friend
=> "Son and Dad have a lot of friends"

#完全可以用老爸的受保護方法
dd.son_money
=> "Son and Dad have a lot of money"

#完全可以用老爸的私用方法
dd.son_company
=> "Son and Dad have a lot of company"

#在自己的私用方法中也可以呼叫到老爸的所有類型的方法
dd.son_all
=> "hey hey A__A i told you a secret:"
       "Dad have a lot of friends"
       "Dad have a lot of money"
       "Dad have a lot of company"

這個故事告訴我們,越後面出生的越幸福(誤),不過好像也可以這麼作結論,孩子的東西永遠比父母多,而且父母有的孩子一定有!QQ

=================================================

23天了!!!

Go ahead, let them judge you.

繼續前進,做足準備,再讓大家審視我!!XD


上一篇
Ruby女孩(22):公用、受保護、私用方法大亂鬥
下一篇
Ruby女孩(24):模組是不生孩子的!模組與類別差異及mixin介紹
系列文
Ruby女孩:10萬.times { puts "為什麼?" }30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言