# 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 專案中,模組用在哪些地方?****
**到家**