# Ruby(03/14) Day 29 五倍紅寶石(第八屆共筆)(2021/8/05) ## Object-Oriented Programming(OOP) 物件導向程式設計 使用人類比較容易理解的概念, 主要核心概念是傳遞訊息,物件與物件之間的**連結**才是重點,不要被名字給影響。 物件好用的地方在於能夠使用方法去跟別的物件互動,才有辦法幫我們做事。 物件 = 狀態(名詞) + 行為(動詞)。 在 Ruby 裡幾乎所有東西都是物件。 只有 **block 跟 method** 不是物件。 ### 方法補充 Ruby 不像 JS 有高階函式,不能用方法回傳方法。 定義方法時,Ruby 會將方法的名稱宣告成符號。 有興趣了解更多OOP的概念可以看下面這部影片,是之前龍哥貼的影片其中一位講得很好的講者講的。 [Object Oriented Programming is not what I thought - Talk by Anjana Vakil](https://www.youtube.com/watch?v=TbP2B1ijWr8) ## 類別&實體 ### 類別 Ruby 的類別也是物件,別的程式不一定。 - 定義: 定義類別要用大寫英文開頭,也就是用**常數**定義。 - 用處: - 用來分類,把同樣特徵的都歸在同一類 - 類別可以產生實體,把方法定義在裡面就可以讓他生出來的實體去用 #### 類別方法 = **作用在類別上的方法 = 他被類別呼叫,所以他就是類別方法**。 類別方法會被定義在那個類別裡面。 all 接在 Cat 後面,Cat 是類別,所以 all 是類別方法。 self = JS 的 this,指這個類別本身,方便使用。 誰呼叫誰就是 self,這邊的 self 就是 Cat 本身。 以後如果要修改 Cat 名稱也沒差,不用改函式裡面的名字。 ```=rb class Cat def self.all puts "全部的貓兒" end end Cat.all ``` - 如何定義: ```=rb # 方法1: class Cat def self.all puts "全部的貓兒" end end Cat.all # 方法2: class Cat class << self def all puts "全部的貓兒" end end Cat.all # 方法3: class Cat end def Cat.all puts "全部的貓兒" end Cat.all ``` ### 實體 #### 實體方法 = **作用在實體上的方法 = 他被實體呼叫,所以他就是實體方法**。 實體方法會被定義在那個實體的類別裡面。 say_hello 接在 kitty 後面,kitty 是 Cat 類別生出來的實體,所以 say_hello 是實體方法。 ```=rb class Cat def say_hello puts "你好" end end kitty = Cat.new kitty.say_hello ``` 實體方法是共用的,讓生出來的實體都有共同行為。 ex:都會走路 - 如何定義: ```=rb # 方法1: class Cat def all puts "全部的貓兒" end end Cat.new.all # 方法2: class Cat attr_accessor :all end kitty = Cat.new kitty.all = "全部的貓兒" p kitty.all ``` ### initialize 初始化 透過 new 可以建立實體, 被 new 出來的物件會立即做 initialize 裡面的方法,還沒呼叫他就會執行了。 可以帶引數給他,變成他的參數,但多給或少給都會出錯 (ArgumentError)。 預設 initialize 裡面是空的。 - why? 一出生就會做事,生出來有預設值,比較方便做事。 #### 類別變數 @@開頭的 在類別方法裡可取用的變數。 ```rb class Cat @@count = 0 def initialize @@count += 1 end def self.counter return @@count end end 5.times { Cat.new } # 印出 5 p Cat.counter ``` #### 實體變數 @開頭的 在實體裡面可以自由取用的變數,定義在類別裡,不能直接在外面拿到,要透過方法回傳到外面。 實體變數只會存活在個別的實體上(傳進去的'kitty'只會活在 kitty 實體上),資料可以透過 new 後面的引數傳進去。 ex: 個別資料:名字、住哪、電話幾號等等的。 如果直接在外面使用 name 方法會發生 NoMethodError,因為 Cat 裡面根本沒有 name 這個方法可以用。 ```=rb class Cat def initialize(name) @name = name end def say_my_name return @name end end kitty = Cat.new('kitty') puts kitty.say_my_name ``` #### new 跟 initialize 的關係: new 是用來生實體出來的,後面帶進去的引數會傳給 initialize 當他的參數用。 參數又會指派給實體變數,接著用方法讓他傳到外面才能被呼叫出來。 #### 小結: - 實體變數@ 在實體方法裡可以自由取用的變數。 只能活在類別裡面,想拿出去要透過實體方法傳出去,用在呼叫實體方法時要把值帶出來的時候。 方法是共用的,實體變數只會存活在個別的實體上。 - 類別變數@@(少用) 在類別方法裡可取用的變數。 只能活在類別裡面,想拿出去要透過類別方法傳出去,用在呼叫類別方法時要把值帶出來的時候。 - 實體方法 作用在實體上的方法 = 他被實體呼叫,所以他就是實體方法 - 類別方法 作用在類別上的方法 = 他被類別呼叫,所以他就是類別方法 --- ## singleton method 單點方法 可以再任意物件上定義任意方法 = 只會對那顆物件有效的方法,不過通常不會這樣用。 因為類別也是物件,所以可以在 Dog 類別上建立方法。 ```rb class Dog def self.fly = Dog.fly = singleton method end end Dog.fly ``` ### main 外面的 self = main main 是 Object 類別所建立的實體,也就是說 main = Object.new。 誰呼叫誰就是 self,self 沒人呼叫就是代表外面的大泡泡 = 整個 Ruby 執行環境。 ```rb p self => 印出 main ``` ## 如何拿出、取用實體、類別變數 ### 正常拿取:使用 getter & setter - getter 用來把變數拿出去 - setter 用來把變數射進來 setter 後面加 = 是慣例、語法糖衣,為了讓他看起來像是在設定屬性的值給他,但其實 Ruby 根本沒有屬性只有方法,=只是name的一部分而已,這個方法的名字就叫做name=。 ```=rb class Human def initialize(name) @name = name end # getter 拿出:把拿小孩出去 def name @name end # setter 接收:射進來 def name=(new_name) @name = new_name end end eddie = Human.new("eddie") # 印出 "eddie" p eddie.name eddie.name = "Ruby" # 印出 "Ruby" p eddie.name ``` ### 懶人拿取法:使用 attr_reader、attr_writer、attr_accessor 是屬性快捷鍵 = 類別方法。 - attr_reader = 可讀 = getter - attr_writer = 可寫 = setter - attr_accessor = 可讀可寫 = 融合 getter + setter - 用法:可用符號或字串來取用,本身是方法,()內是參數 attr_accessor(:name, :age) attr_accessor :name, :age => 通常會省略() 為什麼有可讀可寫還要有可讀跟可寫功能? => 權限控管,有的事情不要開放讓使用者用。 ex:讓使用者自己修改帳戶的錢會很可怕。 ## open class 開放類別 同名 class 可重複定義 class ,裡面的方法如果名字不同不會被蓋掉,會融合在一起。 但如果裡面的方法也同名那後面的方法會蓋掉前面的。 應用:可以幫所有物件(包括原生類別)定義(增加)方法。 ```rb class A def aa end class A def aa def bb end ``` - **常數可以被修改是為了讓 open class 能正常運作** 以上面例子為例: 1. 建立 class A,裡面有方法 aa 2. Ruby 看到又建立一個名字一樣的 class A 會建立一個新的物件 3. 把前面的 class A 指向新物件(這時候常數被 reassigned) 4. 把後面的 class A 裡面的方法加進去新物件 5. 發現有同名的方法,後面的 def aa 會蓋掉前面的 ## Object Model - a.class 可以看到 a 物件是誰生出來的,找他的 class。 - a.superclass 可以找到上層的 class。 - 所有的class的class都是class,包括他自己 可用 .class 搭配 .superclass 找到最上層的人是誰。 類似 JS 的找原型,JS 是往末端找(沒有繼承的概念),Ruby 是往上層找(有繼承的概念)。 當使用方法的時候,如果 Ruby 在他的 class 找不到這個方法就會一直往上層找,直到找到為止。 例子: ```rb class Animal end class Cat < Animal def initialize(name) @name = name end def say_my_name return @name end end kitty = Cat.new('kitty') kitty.class = Cat Cat.superclass = animal . . . kitty => animal => Object => BasicObject => nil => NoMethodError ``` class 的上層是 module 再往上會回到 Object ```rb class.superclass => module => Object ``` ## Rake 是 Ruby 實做的伺服器的介面,不是伺服器,是網頁跟伺服器中間的橋樑。 ROR是一種Rack的大型應用程式。 request:我輸入的內容 response:輸出結果 - Rake 是一種規格,會提供一個能夠回應 call 方法(call 方法是用來執行物件的方法)的物件(使用 Proc 或 lambda 讓 block 變成物件,才可以用 call 方法)給網頁,並回傳一個包含以下三個元素的陣列: - 狀態(數字) - header(Hash) - body(陣列) - HTTP 狀態碼: - 1開頭:參考資訊 - 2開頭:成功 - 3開頭:重新導向(轉址) - 4開頭:使用者的錯 404:我這邊沒東西,你硬要來我這邊找。 header、body正確還是可以看得到網站內容,用404表示不存在,跟 nil 一樣。 - 5開頭:伺服器的錯 伺服器找不到這個頁面 指令: - rackup 執行 - control c 停止它 - PATH_INFO 找哪個網址(路徑) ## Rails 是Ruby的加強版,用開放類別幫現有類別做了很多擴充,多了很多好用的方法。 --- ###### tags: `Ruby`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up