# Class,Model [toc] # Class - ****什麼是物件?**** 物件是實體 > 物件(Object)= 狀態(State)+ 行為(Behavior) - ****什麼是類別?**** 類別是抽象的 一個描述物件內容的概念 類別命名需為常數(開頭為大寫) - ****定義類別**** ```ruby class Cat #...要做的事情 end #實例化 kitty = Cat.new ``` - ****初始化**** ```ruby class Cat def initialize(name, gender) #建構參數 @name = name @gender = gender end def say_name puts " My name is #{@name} " end end kitty = Cat.new("kitty", "female") kitty.say_name #=> My name is kitty ``` - ****實體變數(instance variable)**** ```ruby class PostsController < ApplicationController def index @posts = Post.all # 取得所有的 Post 資料 end end ``` - ****取用實體變數**** 實體變數無法從外部取用,因Ruby沒有屬性(property/attribute)這樣的設計,要取用實體變數,需要另外定義的方法 ```ruby class Cat def initialize(name, gender) @name = name @gender = gender end def say_hello puts "hello, my name is #{@name}" end def name @name end def name=(new_name) @name = new_name end end kitty = Cat.new("kitty", "female") kitty.name = "nancy" ##此處調用的方法是 name= 並非 name puts kitty.name # => nancy ``` - Ruby預設的**attr方法reader, writer, accessor** attr_reader ⇒ 讀取 attr_writer ⇒ 設定 attr_accessor ⇒ 讀取、設定 ```ruby class Cat attr_accessor :name def initialize(name, gender) @name = name @gender = gender end def say_hello puts "hello, my name is #{@name}" end end ``` - ****實體方法與類別方法**** 依據作用的對象不同,有分實體方法(instance method)及類別方法(class method) ```ruby kitty = Cat.new("kitty", "female") kitty.say_hello ###<= say_hello就是作用在kitty的實體 class PostsController < ApplicationController def index @posts = Post.all # 取得所有的 Post 資料 # all作用在Post這個類別上,所以為類別方法 end end ``` Ruby要定義類別有幾種寫法 常見的為使用self: ```ruby class Cat def self.all # ... end end #要調用時使用call呼叫 => Cat.call #=============另外一種寫法 class Cat class << self def all #... end end end ``` ## 方法的存取控制 public - 所有人都能直接存取 private - 只有內部類別才能存取 protected - 兩者之間,比 private 寬鬆一些,但又沒有 public 那麼自在,protected 在同一個類別內或是同一個 package,或是繼承它的子類別可以自由取用,但如果不是的話則不可存取。 Ruby設定的方式: ```ruby #寫在定義之前 class Cat def eat puts "好吃!" end protected def sleeping puts "zzzzzzzzz..." end private def gossip puts "我跟你說,你不要跟別人說喔!" end end #寫在定義之後 class Cat def eat puts "好吃!" end def sleeping puts "zzzzzzzzz..." end def gossip puts "我跟你說,你不要跟別人說喔!" end protected :sleeping private :gossip end ``` Ruby 冷知識: > 沒有特別限制的方法預設都是 public,但除了一個例外,就是負責初始化的initialize方法,它永遠是 private 的,只會被new方法呼叫。而這三者都不是關鍵字,只是一般方法。 > 與其他語言不同的特性: ```ruby kitty = Cat.new kitty.eat # => "好吃!" kitty.sleeping # => NoMethodError kitty.gossip # => NoMethodError ##這裡的 kitty.eat ##不是單純「kitty物件調用了eat方法」而已 ##Ruby解讀為「有一個kitty物件,發送了eat這項訊息(message),而kitty就是這個訊息的receiver」 ``` ### Private? ```ruby class Cat def say_hello self.gossip end private def gossip puts "我跟你說,你不要跟別人說喔!" end end kitty = Cat.new kitty.say_hello # NoMethodError kitty.gossip # => NoMethodError #在類別裡沒有明確的接收者,所以上述都會出現錯誤,但在下例程式碼,使用send把gossip當成參數傳遞給kitty就沒有違反規定 kitty.send(:gossip) # => 我跟你說,你不要跟別人說喔! ``` - ****繼承(Inheritance)**** ```ruby class Cat def eat(food) puts "#{food} 好好吃!!" end end class Dog def eat(food) puts "#{food} 好好吃!!" end end #以上Cat,Dog類別裡都有定義eat的方法 ``` 在OOP概念裡,重複的方法應該獨立出來定義,再去繼承他 ```ruby class Animal def eat(food) puts "#{food} 好好吃!!" end end class Cat < Animal end class Dog < Animal end ``` 有重複名稱的類別,將會融合 ```ruby class Cat def abc # ... end end class Cat def xyz # ... end end #會變成 class Cat def abc # ... end def xyz # ... end end ``` Open Class(開放類別) ```ruby class String def say_hello "hi, I am #{self}" end end puts "eddie".say_hello # => hi, I am eddie puts "kitty".say_hello # => hi, I am kitty ``` # 模組(Module) - ****類別跟模組寫起來好像?**** ```ruby #宣告模組 module Flyable def fly(name) puts "#{name} can fly!!" end end class Cat include Flyable end kitty = Cat.new kitty.fly('Kitty') #=> " Kitty can Fly " ``` 模組為類別的上層,與類別不同的地方為 1. 模組無法實體化 2. 模組無法繼承模組 > 如果你發現你要做的這個功能,它可能在很多不同體系的類別裡都會用得到,那你可以考慮把功能寫在模組裡,需要的時候再 include 進來即可。但如果你還是不知道到底類別跟模組有什麼差別,我再舉二個例子。不知道大家有沒看過[火影忍者](https://goo.gl/4zDQga)這部漫畫,漫畫裡的主人公之一,宇智波佐助,因為他們家族血統的關係,他寫輪眼這個功能是天生就有的,你可以想像他這個功能算是從他的家族「繼承」來的。而佐助的老師,旗木卡卡西,他雖然也有寫輪眼功能,但他的寫輪眼並非繼承來的,事實上是他在年輕時候include 了某位朋友的寫輪眼模組,所以才有這個效果。另一個例子,[海賊王](https://zh.wikipedia.org/wiki/ONE_PIECE)漫畫裡,主角魯夫本來是普通人,但在偶然的機會下,他 include 了橡膠果實之後,他就有了橡膠人的能力了,並不是因為他老爸是橡膠人所以他才是橡膠人。 > - ****在 Rails 專案中,模組用在哪些地方?**** **到家**