我眼中的元編程-對象模型篇

作為一個Ruby開發(fā)者雪营,讓人又愛又恨的便是元編程了蔚晨。

【前言】元編程是什么

簡單地說盟戏,元編程就是對語言本身的進行操作的一種編程手段板祝,最常見的就是代碼生成代碼宫静。對于Ruby這門語言而言,不會元編程券时,等于不會這門語言孤里,因為這是它的核心能力與魅力。本文是基于閱讀《Ruby元編程》后記錄的一些自己的理解和看法橘洞。

元編程示例【示例1】
module Kernel
  def attr_access(*args)
    args.each do |arg|
      define_method(arg) do
         instance_variable_get("@#{arg}")
      end
      define_method("#{arg}=") do |val|
        instance_variable_set("@#{arg}", val)
      end
    end
  end
end

class Student
  attr_access :name, :age
end

stu = Student.new
stu.age = 20
stu.name = 'Rapheal'

p stu.inspect

【示例1】一個典型元編程的例子捌袜,它實現(xiàn)了Ruby中自帶的attr_accessor相同的功能,作用是動態(tài)的為傳入的參數(shù)(上面代碼中是:name:age)添加settergetter方法(stu.age=xxx為其setter方法, stu.age為其getter方法)炸枣。這樣的方法避免了類似Java中的長篇settergetter定義虏等。

【主題】對象模型

Ruby作為一種完全面向?qū)ο蟮木幊陶Z言,即使是一個數(shù)字抛虏、類博其、甚至一個方法都是一個對象套才。所謂對象迂猴,就是能對它進行一系列操作的一個集合。

打開類

對象模型篇第一講就是打開類背伴。在【示例1】代碼中其實就已經(jīng)包含了打開類的一種具體實現(xiàn)方法沸毁。打開類峰髓,即打開一個已經(jīng)存在的類或?qū)ο螅瑸槠?code>添加新方法息尺、修改已存在的方法刪除不需要的方法的一種技術(shù)携兵。在【示例1】中,Kernel是Ruby庫中已經(jīng)存在的一個模塊搂誉,使用module Kernel將其重新打開徐紧,并添加了一個新方法attr_access。于是Kernel模塊便在原來的基礎(chǔ)上新增了一個方法attr_access炭懊。

修改一個已經(jīng)存在的方法【示例2】
str = "abc"
p str.to_s # 這里會輸出"abc"
class String
  def to_s
    "Nothing"
  end
end
str = "abc"
p str.to_s # 這里輸出的就是"Nothing"了

String也是Ruby庫自帶的類并级,to_sString類已存在的方法,當(dāng)重新打開它并重寫了to_s方法之后侮腹,原來方法的作用便不復(fù)存在了嘲碧,取而代之的是新方法的作用。(這種修改已經(jīng)存在的方法又被稱為猴子補丁

打開類的利與弊

通過【示例1】【示例2】的代碼可以知道父阻,打開類技術(shù)可以很好的對已經(jīng)存在的類或方法進行修改愈涩,使之更符合個人的使用需求。然而加矛,若不加以思考隨意使用履婉,帶來的問題也是很嚴重的。比如String類的to_s方法斟览,作用就是要返回本身這個字符串谐鼎,結(jié)果被別人修改了這個定義,導(dǎo)致了所有引用這個方法的代碼全部失去了它本來的功能與意義趣惠。因此在使用打開類定義一個方法時狸棍,需要謹慎,盡量取一個當(dāng)前不存在的方法名來新定義一個方法味悄。

對象中有什么

首先草戈,實例變量,如【示例1】中的:name:age侍瑟,當(dāng)調(diào)用stu.name = 'rapheal'之后唐片,stu對象便產(chǎn)生了一個實例變量@name實例變量必須是以【一個@符號】開頭的變量名涨颜。這時可以通過調(diào)用stu.instance_variables來查看已經(jīng)存在的實例變量费韭,可以看到輸出中有:@name這一條。

其次庭瑰,方法星持。通過stu.methods可以查看stu對象能調(diào)用的所有方法。Ruby對象共享方法弹灭,但不共享實例變量督暂,共享的方法被稱為【實例方法】揪垄。【實例方法】定義在對象的類中逻翁,這樣可以使得同一類對象可以調(diào)用相同的方法饥努。

類也是對象。類對象所屬的類是Class類八回。類的方法即為Class類中定義的【實例方法】酷愧。比如,所有類都有一個方法new,而new方法的定義就在Class類中缠诅。我們甚至可以簡單的認為:ClassA = Class.newclass ClassA; end是等價的伟墙。它們都是在定義一個新的類ClassA

方法查找

提到方法查找滴铅,那么首先要知道的就是祖先鏈戳葵。祖先鏈其實就是記錄的一個類的繼承關(guān)系的一個列表,可以通過調(diào)用ancestors方法來查看汉匙。比如String.ancestors返回的是[String, Comparable, Object, Kernel, BasicObject]拱烁,于是我們可以判斷,String類繼承自Object噩翠,(ComparableKernel是兩個module,它被包含在了其中的某個類中戏自,也會出現(xiàn)在祖先鏈中來,此處我們不討論祖先鏈中的module)伤锚,Object又繼承自BasicObject擅笔。

理解了方法鏈,再回頭來看方法查找屯援。Ruby中的方法查找有個原則叫作向右猛们,再向上。比如狞洋,有一個String類的對象str弯淘,調(diào)用方法str.test_call_method,這時Ruby解釋器會:

  • 1吉懊、【向右】來到str所屬的String類查看String類是否定義了test_call_method這個方法庐橙,若定義了則直接調(diào)用
  • 2、【向上】否則查看Comparable這個module中是否定義這個方法(因為祖先鏈中有這個module借嗽,并且排在了第二個态鳖,即String類和Object類中間)
  • 3、【向上】若還未定義恶导,則來到父類Object類查找
  • 4浆竭、重復(fù)上述2、3步驟直到BasicObject

上述步驟中,步驟1稱為向右兆蕉,步驟2羽戒、3稱為向上缤沦。整個流程中虎韵,可以看出,方法查找是優(yōu)先向右(所屬類)查找缸废,再向上(優(yōu)先是自身包含的模塊然后是父類)查找包蓝。因此稱為向右,再向上原則企量。

對于類所包含的模塊會在方法查找時定義為一個匿名類并插入到祖先鏈中該類的直接上方测萎。

關(guān)于self

在某個特定時刻,一定會有一個指定的對象在執(zhí)行届巩,這個對象就是self對象硅瞧。最開始接觸這個的時候,會有一個誤區(qū)認為self是當(dāng)前調(diào)用方法的執(zhí)行者恕汇,然而事實上self是當(dāng)前方法執(zhí)行的接收者腕唧。簡單說即是,當(dāng)前方法調(diào)用的結(jié)果會傳遞返回給這個self對象瘾英。

談到self枣接,那么就應(yīng)該順便說一下private。Ruby中的private是和self相關(guān)的缺谴,在Ruby類的定義的private方法是不能被顯式調(diào)用的但惶。

private示例【示例3】
class A
   def print_self
      self.t_pri
   end
   def print_self_2
      t_pri
   end
   private
      def t_pri
        p "hello world"
      end
end

obj1 = A.new
obj1.print_self_2 # 輸出 "hello world"
obj1.print_self     # 報錯, NoMethodError: private method 't_pri' called
obj1.t_pri            # 報錯,同上

【示例3】湿蛔,可以看出私有方法t_pri只能由self隱式調(diào)用膀曾,即私有方法只能在定義的內(nèi)部以直接調(diào)用方式調(diào)用,而不能在任何地方以 xxx.yyyy的方式調(diào)用阳啥。同時妓肢,若沒有顯式指定方法接收者,那么調(diào)用方法的接收都將隱式指定為self對象苫纤。

第一章對象模型基本上就這些內(nèi)容碉钠,了解對象基本模型對于以后編寫Gem包等擴展有相當(dāng)重要的作用,尤其是self對象卷拘。以后的章節(jié)講到扁平作用域的時候會對self對象有更加深刻的描述喊废,如果這些技能不熟練,要編寫Gem擴展真的是舉步維艱栗弟。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末污筷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瓣蛀,老刑警劉巖陆蟆,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惋增,居然都是意外死亡叠殷,警方通過查閱死者的電腦和手機瞻讽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門阿逃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蹄梢,你說我怎么就攤上這事稽亏『埃” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵截歉,是天一觀的道長胖腾。 經(jīng)常有香客問我,道長瘪松,這世上最難降的妖魔是什么咸作? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮凉逛,結(jié)果婚禮上性宏,老公的妹妹穿的比我還像新娘。我一直安慰自己状飞,他們只是感情好毫胜,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著诬辈,像睡著了一般酵使。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上焙糟,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天口渔,我揣著相機與錄音,去河邊找鬼穿撮。 笑死缺脉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的悦穿。 我是一名探鬼主播攻礼,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼栗柒!你這毒婦竟也來了礁扮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎太伊,沒想到半個月后雇锡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡僚焦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年锰提,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叠赐。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡欲账,死狀恐怖屡江,靈堂內(nèi)的尸體忽然破棺而出芭概,到底是詐尸還是另有隱情,我是刑警寧澤惩嘉,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布罢洲,位于F島的核電站,受9級特大地震影響文黎,放射性物質(zhì)發(fā)生泄漏惹苗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一耸峭、第九天 我趴在偏房一處隱蔽的房頂上張望桩蓉。 院中可真熱鬧,春花似錦劳闹、人聲如沸院究。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽业汰。三九已至,卻和暖如春菩颖,著一層夾襖步出監(jiān)牢的瞬間样漆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工晦闰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留放祟,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓呻右,卻偏偏與公主長得像跪妥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子窿冯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理骗奖,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法执桌,類相關(guān)的語法鄙皇,內(nèi)部類的語法,繼承相關(guān)的語法仰挣,異常的語法伴逸,線程的語...
    子非魚_t_閱讀 31,631評論 18 399
  • 20- 枚舉,枚舉原始值,枚舉相關(guān)值,switch提取枚舉關(guān)聯(lián)值 Swift枚舉: Swift中的枚舉比OC中的枚...
    iOS_恒仔閱讀 2,278評論 1 6
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,967評論 6 13
  • 當(dāng)你在明亮舒適的休息室,喝著水膘壶,不斷敲打鍵盤错蝴,偶爾看看窗外,現(xiàn)在的我除了畢業(yè)的事忙碌一些颓芭,也沒有其他的事了顷锰,很快就...
    愿暖閱讀 110評論 0 0