類別與模組是 Ruby 物件導向精神的重中之重,第二天有提到,在Ruby 裡面幾乎萬物皆物件
物件(object)是什麼?
物件是承載資料與行為的東西,物件行為就是物件的方法,資料就是昨天提到的變數,被物件帶在身上。
如果有些物件的行為有相似之處,就可以把它們歸在同一類,也就是同一個類別 class
。類別可以說是物件的模子,可以製造一個個具有相似行為的物件,用龍哥的例子來說,類別vs物件
就像雞蛋糕模具vs雞蛋糕
的關係。
class Animal
def initialize(name)
@name = name
end
def shout #定義物件方法
p "我的名字是#{@name}"
end
end
initialize 是類別的初始化方法,注意不要拼錯字喔(我就是拼錯兩次以上的人 (/‵Д′)/~ ╧╧)
上面定義了Animal類別,模具已經準備好,可以來印出兩隻小動物
animal1 = Animal.new('Lucky')
animal2 = Animal.new('Luke')
animal1.shout # => "我的名字是Lucky"
animal2.shout # => "我的名字是Luke"
這樣就產生行為相似,但資料不同的兩個物件。
想在動物類別Animal
的基礎上,產生狗類別Dog
跟貓類別Cat
。就可以使用類別繼承(inherit)來使用已經定義好的Animal
方法,加上屬於自己的方法。
![Imgur](https://i.imgur.com/30iiWCO.png =500x)
class Dog < Animal
def bark
p "#{@name}會汪汪叫"
end
end
class Cat < Animal
def meow
p "#{@name}會喵喵叫"
end
end
doggy = Dog.new('風速狗')
kitten = Cat.new('貓老大')
doggy.bark #=> "風速狗會汪汪叫"
kitten.meow #=> "貓老大會喵喵叫"
實務上使用Rails開發網站時,會把相同特性放在上層controller,讓下層的controller直接繼承,每個下層controller就不用把相同的行為都寫一次,既讓程式碼簡潔,又符合 Ruby的精神:DRY(Don't Repeat Yourself)
。
例如所有後台的controller,使用者都應該要登入才能進入,可以先定義一個AdminController
,把登入驗證的邏輯寫在這裡,讓其他的controller去繼承他。
如果有些方法,整個類別都有特性,跟個別實體身上的資料無關,可以使用類別方法。比方說,所有動物都會呼吸,定義breath
方法時前面要加self
。
class Animal
def self.breath
p "呼~"
end
end
Animal.breath # => "呼~"
假設有個方法部分類別會用到,我們可以用剛才提過的類別繼承,把這個方法放在上層類別。但這樣做有個缺點,連不需要這些方法的類別都有這個方法。這時候該是模組出場的時候啦。
模組類似我們在RPG遊戲裡的裝備,類別只要裝上了這個模組,就擁有這個模組所有的方法。
比如說,我希望高手
類別都配備弓箭
模組讓攻擊距離加大
module Arrow
def send
p "#{@name}攻擊範圍提升1.5倍"
end
end
class Master
include Arrow
def initialize(name)
@name = name
end
end
透過include
方法,把Arrow
模組加在Master
類別上。
來感受一下模組的威力
robin_hood = Master.new('羅賓漢')
robin_hood.send # => "羅賓漢攻擊範圍提升1.5倍"
有沒有覺得模組讓本來的類別能力up了呢?
看完上面的例子,你或許覺得模組跟類別都可以定義物件方法,到底有什麼差別?
最大的差別有三個
1.class 可以透過內建的new
方法來實體化物件,Moduel不行
2.class 可以繼承取得其他class的特性,Module不行
3.Module 有include或exclude方法來擴充class,但class不能被inlcude 進其他class