Ruby的Forwardable模塊瞎扯淡

回想起咱門初學(xué)C跟Java語(yǔ)言的時(shí)候,或許會(huì)以為這個(gè)世界上只有這兩門語(yǔ)言。 當(dāng)時(shí)老師或者教科書肯定不是一上來就教你如何用這門語(yǔ)言去連接數(shù)據(jù)庫(kù),而是要求你用這門語(yǔ)言去實(shí)現(xiàn)一些簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu),以及排序這類簡(jiǎn)單的算法。Oh,sorry,我可能讓你回憶起一些不太好的事情了。特別是后來背棄了編程這條路的同學(xué),你們一定覺得這個(gè)過程特別的枯燥,而且艱辛。

還記得那時(shí)候我們?yōu)榱藢?shí)現(xiàn)一種叫做先進(jìn)先出的被呼喚為隊(duì)列的數(shù)據(jù)結(jié)構(gòu),以及一種后進(jìn)先出的被呼喚為棧的數(shù)據(jù)結(jié)構(gòu)耗費(fèi)了我們多少時(shí)間了嗎?現(xiàn)在的你肯定不會(huì)手動(dòng)去寫這些數(shù)據(jù)結(jié)構(gòu)了,別人早就寫好的代碼很容易就能夠在網(wǎng)上找到,我們直接用便可(當(dāng)然那時(shí)候我們不知道有Github這種東西)。

隊(duì)列

后來,我決定要走一條不尋常的路(研習(xí)一門動(dòng)態(tài)語(yǔ)言)的時(shí)候。我發(fā)現(xiàn)更不用做這些事情了,所謂的棧,隊(duì)列,這些數(shù)據(jù)結(jié)構(gòu),在許多語(yǔ)言的內(nèi)置庫(kù)里面都已經(jīng)有類似的實(shí)現(xiàn)。今天,請(qǐng)?jiān)试S我用Ruby來講這個(gè)事情,另外我會(huì)結(jié)合Ruby的Forwardable模塊,優(yōu)雅地實(shí)現(xiàn)方法代理。

1. 簡(jiǎn)單模擬棧跟隊(duì)列

Ruby的內(nèi)置類 Array的存在,為我們簡(jiǎn)單操作序列型數(shù)據(jù)提供了可能,我們只需要用字面量的方式就能夠很容易地創(chuàng)建一個(gè)序列

array = [1,2,3,4]
=> [1, 2, 3, 4]

然后?我們可以基于Array的實(shí)例來簡(jiǎn)單地模擬?;蛘哧?duì)列的行為。

1)模擬棧

我只需要簡(jiǎn)單地使用Array#shift以及Array#unshift兩個(gè)實(shí)例方法就能夠很簡(jiǎn)單地模擬棧的功能

# 棧的實(shí)現(xiàn)
pry(main)> array
=> [1, 2, 3, 4]
pry(main)> array.unshift(1)
=> [1, 1, 2, 3, 4]
pry(main)> array.shift()
=> [1]
pry(main)> array
=> [1, 2, 3, 4]

是不是很簡(jiǎn)單?我只需要反復(fù)調(diào)用上面兩個(gè)方法,就能夠完成棧能完成的事情了。

2)模擬隊(duì)列

接下來模擬隊(duì)列,隊(duì)列也比較簡(jiǎn)單,我們只需要調(diào)用Array#push方法就可以在隊(duì)列的末尾插入一個(gè)元素。然后通過Array#shift方法,移除并獲取隊(duì)列頭部的元素。

# 隊(duì)列的實(shí)現(xiàn)
pry(main)> array
=> [1, 2, 3, 4]
pry(main)> array.push(1)
=> [1, 2, 3, 4, 1]
pry(main)> array.shift()
=> [1]
pry(main)> array
=> [2, 3, 4, 1]

但是如果在平時(shí)的業(yè)務(wù)代碼中我們給隊(duì)友們提供這樣的隊(duì)列,或者棧的話。你可能就見不到明天的太陽(yáng)了,我相信軟件行業(yè)里面爛代碼吸引的仇恨,并不亞于英雄聯(lián)盟里面的豬隊(duì)友。那我們一般會(huì)怎么做?請(qǐng)接著往下讀。

2. 定義隊(duì)列或者棧的相關(guān)類

更加語(yǔ)義化的方式是定義相關(guān)的類(Stack,Queue),然后封裝對(duì)應(yīng)的操作方法。這樣,當(dāng)別人用到我們定義好的有特定行為的類的時(shí)候心情就會(huì)更加舒坦。我們代碼可讀性也更高。我開篇一直在扯語(yǔ)言的事情,就是提醒一下在我們使用動(dòng)態(tài)語(yǔ)言的時(shí)候,請(qǐng)盡量跳出靜態(tài)語(yǔ)言的思維定勢(shì)。很多事情其實(shí)可以更簡(jiǎn)單。動(dòng)態(tài)語(yǔ)言往往更關(guān)注行為,而不是類型。

1) 屌絲方案

class Queue
  def initialize
    @q = []
  end

  def enq(*argument_list)
    @q.push(*argument_list)
  end

  def deq(*argument_list)
    @q.shift(*argument_list)
  end
end

我知道現(xiàn)在的代碼并不是很好看,但是請(qǐng)相信我,最起碼它是可以運(yùn)行的

pry(main)> q = Queue.new
=> #<Thread::Queue:0x007ff00f0ccfe0 @q=[]>
pry(main)> q.enq(1,2,3,4)
=> [1, 2, 3, 4]
pry(main)> q
=> #<Thread::Queue:0x007ff00f0ccfe0 @q=[1, 2, 3, 4]>
pry(main)> q.deq()
=> 1
pry(main)> q
=> #<Thread::Queue:0x007ff00f0ccfe0 @q=[2, 3, 4]>
pry(main)> q.deq(2)
=> [2, 3]
pry(main)> q
=> #<Thread::Queue:0x007ff00f0ccfe0 @q=[4]>

雖然有點(diǎn)粗糙,但最起碼它也是一個(gè)隊(duì)列。它能夠完成隊(duì)列的基本行為。

2) 高富帥的寫法

初入Ruby難免會(huì)寫出一些比較矮窮搓的代碼,沒事,隨著我們經(jīng)驗(yàn)的累積,我相信我們會(huì)慢慢寫出高富帥的代碼出來。為了讓上述的代碼更簡(jiǎn)短一些,我們可以增強(qiáng)原有類的功能。Ruby經(jīng)常會(huì)使用Module來完成增強(qiáng)任務(wù)。下面介紹一個(gè)叫做Forwardable的模塊,它提供了一些好用的類方法,可以幫我們簡(jiǎn)單地定義對(duì)應(yīng)類的一些實(shí)例方法,并且,把定義好的實(shí)例方法代理到實(shí)例變量相關(guān)的某個(gè)方法上。這樣說可能有點(diǎn)迷糊,我這里列舉一個(gè)官方文檔的例子。

require 'forwardable'
class Queue
  extend Forwardable
  def initialize
    @q = []
  end

  def_delegator :@q, :push, :enq
  def_delegator :@q, :shift, :deq
end

沒錯(cuò),已經(jīng)寫完了。這就是Forwardable模塊的最直接的用法,Queue通過擴(kuò)展模塊Forwardable,就會(huì)得到Forwardable::def_delegator這樣的類方法,通過這個(gè)類方法定義實(shí)例方法Queue#enq并把功能代理到Array#push這個(gè)實(shí)例方法上。在解析環(huán)境中運(yùn)行以上代碼。得到的結(jié)果跟之前的例子是一樣的。

pry(main)> q = Queue.new
=> #<Thread::Queue:0x007ff00f0ccfe0 @q=[]>
pry(main)> q.enq(1,2,3,4)
=> [1, 2, 3, 4]
pry(main)> q
=> #<Thread::Queue:0x007ff00f0ccfe0 @q=[1, 2, 3, 4]>
pry(main)> q.deq()
=> 1
pry(main)> q
=> #<Thread::Queue:0x007ff00f0ccfe0 @q=[2, 3, 4]>
pry(main)> q.deq(2)
=> [2, 3]
pry(main)> q
=> #<Thread::Queue:0x007ff00f0ccfe0 @q=[4]>

好吧,我也知道廢話很多,其實(shí)主要想說明兩件事情

  1. 有些東西用動(dòng)態(tài)語(yǔ)言來寫雖然運(yùn)行效率會(huì)稍微慢一點(diǎn),但是勝在靈活,很多時(shí)候我們可以更優(yōu)雅地去實(shí)現(xiàn)一些功能。
  2. Ruby以Plugin的方式來增強(qiáng)原來的類的行為,提供一些方便我們?nèi)粘J褂玫恼Z(yǔ)法糖讓我們的代碼更精煉。*

如上面的Forwardable模塊提供了Forwardable#def_delegator類方法,讓我們可以方便地實(shí)現(xiàn)代理功能,而不需要手動(dòng)地去實(shí)現(xiàn)對(duì)應(yīng)的細(xì)節(jié)。畢竟我們都知道寫得越多錯(cuò)的越多。

3. 寫在最后

這篇文章作為技術(shù)文章似乎有點(diǎn)短,并且瞎扯淡的成分居多。我就是想黑一下Java,然后用Ruby的方式來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的隊(duì)列。主要是為了展示一下Ruby的優(yōu)雅。至于Forwardable模塊,我對(duì)它了解目前還只是停留在應(yīng)用層面。說實(shí)在的我對(duì)它的源碼很感興趣,希望后面有機(jī)會(huì)可以再寫一篇文章深入剖析它的源代碼。(好吧,我也承認(rèn)我不在這篇文章剖析它的源代碼是因?yàn)槲腋揪瓦€沒看懂它源代碼,他們寫得有點(diǎn)深?yuàn)W。)

如果您還覺得意猶未盡時(shí)間尚早,請(qǐng)用Java去實(shí)現(xiàn)相應(yīng)的隊(duì)列以及棧數(shù)據(jù)結(jié)構(gòu)吧。

Java是最好的語(yǔ)言

Happy Coding and Writing !!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,765評(píng)論 25 709
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,757評(píng)論 11 349
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,581評(píng)論 30 472
  • 你不知道的大理和麗江~ 第三天,從大理出發(fā),經(jīng)過蒼山洱海,直奔麗江,今天一天是整個(gè)行程當(dāng)中最有價(jià)值的一天,大理抵達(dá)...
    櫻花開了閱讀 316評(píng)論 0 0
  • 聞到你的氣息 我醉了,聽到你的聲音 我碎了,我甚至聽到了 熱淚浸濕枕頭的聲音 我笑了,一朵火紅色的 玫瑰在我眼簾處...
    如是完美閱讀 214評(píng)論 0 0

友情鏈接更多精彩內(nèi)容