第七章 對象(二)-默認(rèn)對象系統(tǒng)

神圣引用

Perl默認(rèn)的面向?qū)ο笙到y(tǒng)真心小巧葛家,只有3條規(guī)則:

  • 一個類就是一個包
  • 一個方法就是一個函數(shù)
  • 一個引用(blessed,賜福)就是一個對象(我把bless過的引用翻譯成神圣引用盲链,所以一個神圣引用就是一個對象

由這3條規(guī)則东抹,你可以造出任何東西帕识。但僅僅靠這些來構(gòu)建一個大型項目顯然太過簡約潜腻,特別它是缺乏元編程高度抽象的能力。對于超過了幾百行的(現(xiàn)代)程序卡睦,使用Moose是更好的選擇宴胧,然而還有大量的遺留代碼仍然使用的是默認(rèn)的面向?qū)ο笙到y(tǒng)。

前2條規(guī)則表锻,我們已經(jīng)在之前已經(jīng)介紹過了恕齐。內(nèi)置函數(shù)bless的作用就是將類名和引用聯(lián)系起來,之后該引用就成為一個有效的調(diào)用者瞬逊,Perl就能在該引用上進(jìn)行方法的調(diào)度显歧。(通過引用聯(lián)系到類,調(diào)度類中的方法)

構(gòu)造函數(shù)就是創(chuàng)建對象的方法(類方法)确镊。按慣例士骤,構(gòu)造函數(shù)的名字是new(),但這個不是強(qiáng)制的蕾域。

bless有2個操作數(shù)拷肌,一個引用和一個類名。引用可以是任意有效的引用旨巷,空引用也行巨缘;類名是可選項,默認(rèn)為當(dāng)前包名契沫;bless的返回值就是bless過的引用(神圣引用)带猴。一個簡單構(gòu)造函數(shù):

sub new
{
my $class = shift;
bless {}, $class;
}

這個構(gòu)造函數(shù)將調(diào)用者取出來作為類名。你也可以硬編碼類名懈万,但那樣就不靈活了。帶參數(shù)的構(gòu)造函數(shù)在繼承靶病、委托或?qū)С龅臅r候能重用会通。

通過引用的類型就能了解對象實(shí)例是如何存儲自己數(shù)據(jù)的。哈希引用最為常見娄周,但是其他類型的引用也是可以bless成對象的:

my $array_obj = bless [], $class;
my $scalar_obj = bless \$scalar, $class;
my $func_obj = bless \&some_func, $class;

Moose的類定義需要進(jìn)行屬性的聲明涕侈,但Perl的默認(rèn)OO系統(tǒng)要求沒那么嚴(yán)。一個表示籃球運(yùn)動員的類煤辨,存儲球衣號碼和位置裳涛,它的構(gòu)造函數(shù)可能是這樣的:

package Player
{
sub new
{
my ($class, %attrs) = @_;
bless \%attrs, $class;
}
}

創(chuàng)建新球員就是這樣的:

my $joel = Player->new( number => 10, position => 'center' );
my $damian = Player->new( number => 0, position => 'guard' );

它的類方法可以像訪問哈希元素一樣直接訪問對象屬性:

sub format
{
my $self = shift;
return '#' . $self->{number} . ' plays ' . $self->{position};
}

這樣有個問題就是:修改對象的內(nèi)部數(shù)據(jù)可能會破壞其他的代碼,相比而言使用訪問器的方式就更加安全众辨。

sub number { return shift->{number} }
sub position { return shift->{position} }

現(xiàn)在你不得不自己動手編寫那些Moose免費(fèi)為你提供的功能了端三。Moose鼓勵人們使用訪問器、設(shè)置器鹃彻,而不是直接操作對象屬性郊闯。

方法調(diào)度和繼承

給定一個神圣引用$joel,這樣調(diào)用其方法:

my $number = $joel->number;

首先找到類(類跟引用聯(lián)系起來了)$joel,在這里是Player類团赁。下一步Perl會在Player里面去找一個叫number()的函數(shù)育拨。如果函數(shù)不存在,并且Player繼承了一個父類欢摄,那么Perl就去父類里面找熬丧,再往父類的父類里找,依次類推怀挠,直到找到number()锹引,只要找到(任何地方),就以$joel 為調(diào)用者調(diào)用該函數(shù)唆香。

CPAN上有個模塊namespace::autoclean可以幫助你避免因?qū)牒瘮?shù)而引起的名字沖突嫌变。

Moose提供了extends來跟蹤繼承關(guān)系,Perl則使用包全局變量@ISA來跟蹤躬它。方法調(diào)度就是在每一個類的@ISA里面去找父類腾啥。如果InjuredPlayer 類繼承 Player類,你可以這樣寫:

package InjuredPlayer
{
@InjuredPlayer::ISA = 'Player';
}

或使用編譯指令parent冯吓,寫法會更簡單:

package InjuredPlayer
{
use parent 'Player';
}

Moose因?yàn)橛凶约旱脑P痛鎯^承信息倘待,所以會擁有更多的元編程機(jī)會。

你可以繼承多個父類:

package InjuredPlayer
{
use parent qw( Player Hospital::Patient );
}

AUTOLOAD

如果一直沒有找到要調(diào)用的方法,那么Perl就會轉(zhuǎn)而去尋找AUTOLOAD()方法(之前講過的)组贺。你可能意識到了凸舵,某些情況下問題會變得復(fù)雜。在多重繼承中它到底會調(diào)用哪個AUTOLOAD()方法呢失尖?

重寫方法

默認(rèn)OO支持重寫方法啊奄,但它沒有提供機(jī)制來讓你表明:****你要重寫父類方法****。導(dǎo)致的結(jié)果就是掀潮,任何你定義菇夸、聲明、或?qū)氲阶宇惖暮瘮?shù)都會重寫父類中的同名方法仪吧!

要重寫方法庄新,聲明一個同名的方法即可,在重寫的方法內(nèi)部薯鼠,可以用SUPER::來調(diào)用父類方法:

sub overridden
{
my $self = shift;
warn 'Called overridden() in child!';
return $self->SUPER::overridden( @_ );
}

SUPER::前綴就是告訴方法調(diào)度器去父類調(diào)用择诈。你可以提供自定義參數(shù),但一般是@_出皇,記得要將調(diào)用者卸載掉靶呱帧(@_的第一個參數(shù))。

SUPER::有個不好的特性就是恶迈,如果你從其他包導(dǎo)入方法涩金,Perl有可能找不到正確的父類谱醇。 因?yàn)榧嫒菪裕@個特性一直保留著步做。CPAN上的SUPER模塊提供了一種解決方法副渴。
Moose沒有這樣問題。

應(yīng)對神圣引用的策略

默認(rèn)OO系統(tǒng)(神圣引用)小巧但混亂全度,相比而言Mosse更容易使用煮剧,所以應(yīng)該盡可能的選擇Moose。如果你必須要維護(hù)一些使用神圣引用的代碼将鸵,或者你還沒能說服你的團(tuán)隊整體遷移到Moose上來勉盅,這里有些建議,可以幫助你避免一些坑:

  • 在同一個類中不要混合函數(shù)和方法
  • 盡量每個類使用一個.pm文件
  • 遵循默認(rèn)OO系統(tǒng)的標(biāo)準(zhǔn)顶掉,比如構(gòu)造函數(shù)是new()草娜,$self就是調(diào)用者的名字
  • 使用訪問器,即使是在方法中痒筒。 Class::Accessor這個模塊可能對你有用
  • 避免使用AUTOLOAD()
  • 要考慮別人或者別的地方會使用你的類宰闰,bless時使用2個參數(shù),將類拆成最小的行為單元簿透。
  • 使用模塊來幫助你重用代碼移袍,如 Role::Tiny
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市老充,隨后出現(xiàn)的幾起案子葡盗,更是在濱河造成了極大的恐慌,老刑警劉巖啡浊,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件觅够,死亡現(xiàn)場離奇詭異,居然都是意外死亡虫啥,警方通過查閱死者的電腦和手機(jī)蔚约,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涂籽,“玉大人,你說我怎么就攤上這事砸抛∑来疲” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵直焙,是天一觀的道長景东。 經(jīng)常有香客問我,道長奔誓,這世上最難降的妖魔是什么斤吐? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任搔涝,我火速辦了婚禮,結(jié)果婚禮上和措,老公的妹妹穿的比我還像新娘庄呈。我一直安慰自己,他們只是感情好派阱,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布诬留。 她就那樣靜靜地躺著,像睡著了一般贫母。 火紅的嫁衣襯著肌膚如雪文兑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天腺劣,我揣著相機(jī)與錄音绿贞,去河邊找鬼。 笑死橘原,一個胖子當(dāng)著我的面吹牛籍铁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播靠柑,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼寨辩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了歼冰?” 一聲冷哼從身側(cè)響起靡狞,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎隔嫡,沒想到半個月后甸怕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腮恩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年梢杭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秸滴。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡武契,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荡含,到底是詐尸還是另有隱情咒唆,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布释液,位于F島的核電站全释,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏误债。R本人自食惡果不足惜浸船,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一妄迁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧李命,春花似錦登淘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至周叮,卻和暖如春辩撑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仿耽。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工合冀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人项贺。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓君躺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親开缎。 傳聞我的和親對象是個殘疾皇子棕叫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容