學會了怎么創(chuàng)建類, 我們繼續(xù)用它來構建我們的中心內(nèi)容:
class Hammer {
method hammer($stuff) {
say "You hammer on $stuff. BAM BAM BAM!";
}
}
class Gavel {
method hammer($stuff) {
say "You hammer on $stuff. BAM BAM BAM!";
}
}
class Mallet {
method hammer($stuff) {
say "You hammer on $stuff. BAM BAM BAM!";
}
}
但是注意到了嗎? 這三個方法包含了同樣的方法, 在類中重復了。我們必須那樣做如果我們想讓每個 Hammar、Gavel 和 Mallet 有能力擊打的話。(并且那是合理的)。 但是遺憾的是我們不得不把那個方法一式三份。
為什么遺憾? 因為一方面在真實世界中, 方法并不是很彼此相似, 有一天你決定在 hammer 方法中更改某些東西, 并沒有意識到這個方法在三個不同的地方... 這導致了一堆痛苦和難受。
所以我們的新玩具, 類, 展現(xiàn)出了一個問題。我們想在每個類中重用 hammer 方法。一個新的概念, role 來拯救我們來了:
role Hammering {
method hammer($stuff) {
say "You hammer on $stuff. BAM BAM BAM!";
}
}
雖然類經(jīng)常以一個合適的名詞命名, 但是 roles 經(jīng)常以一個分詞命名, 例如 Hammering。這不是一個必須遵守的規(guī)則, 但是它是一個好的經(jīng)驗法則。現(xiàn)在類的定義變的簡單了:
class Hammer does Hammering { }
class Gavel does Hammering { }
class Mallet does Hammering { }
是的, 我們喜歡那樣。
這發(fā)生了什么? 我們在類上使用 does 是干什么用的? role 定義中的所有方法都被拷貝到類定義中。因為它是一個拷貝操作, 所以我們可以使用盡可能多的類。
所以, 我們做的是: 當我們想重用方法的時候把方法放進 roles 里面。
但是好處不止這一點兒。至少有兩個好處:
my $hammer = Hammer.new; # create a new hammer object
say $hammer ~~ Hammer; # "Bool::True" -- yes, this we know
say $hammer ~~ Hammering; # "Bool::True" -- ooh!
所以 $hammer
知道它遵守了(does)Hammering, 我們現(xiàn)在不僅知道了對象屬于哪個類, 還知道了對象并入了什么 role。這很有用如果我們不確定我們處理的是什么類型的對象:
if $unkown_object ~~ Hammering {
$unknown_object.hammer("砸在釘子上"); # will always work
}
一個類能一次接收幾個 roles 嗎? 是的, 它可以:
role Flying {
method fly {
say "Whooosh!";
}
}
class FlyingHammer does Hammering does Flying { }
讓一個類像那樣遵守幾個 roles 引入了一個有意思的可能: 沖突, 當來自兩個不同 roles 的兩個同名方法嘗試占領同一個類時。這時會發(fā)生什么? 好吧, 至少有 3 種可能:
- 第一個 role 贏了。 它的方法住進了類中
- 最后一個 role 贏了。 它覆蓋了之前的方法
- 編譯失敗。沖突必須被解決。
這種情況下選項 3 應該是正確答案。原因和之前相同: 因為類和工程越來越龐大, 程序員可能意識不到兩個 role 之間在哪兒發(fā)生沖突。所以我們標記了它。
role Sleeping {
method lie {
say "水平躺下";
}
}
role Lying {
method lie {
say "說謊...";
}
}
class SleepingLiar does Sleeping does Lying { } # 沖突!
下一個問題, 那么: 當在類中有 role 沖突時, 我們怎么修復它? 簡單: 在類中自己定義一個同名的方法:
class SleepingLiar does Sleeping does Lying {
method lie {
say "Lying in my sleep....";
}
}
如果你想從一個貼別的 role 中調(diào)用一個方法, 語法是這樣的:
class SleepingLiar does Sleeping does Lying {
method lie {
self.Sleeping::lie;
}
}
這就是 roles。它們把可重用的行為混合進類中。