ruby中的鏈式訪問和方法嵌套

來源:互聯網
上載者:User

標籤:style   blog   http   java   color   使用   

  先看一道題,這道題是codewars上的一道題,我很早就看到了,但是不會寫。等到又看到這道題的時候,我剛看完元編程那本書,覺得是可以搞定它的時候了。廢話不多說,先看這道題,題目最開始是為JavaScript寫的,但是也放在了ruby語言裡面,這個沒有關係。題目內容是有一個類Calc,通過鏈式方法調用,可以實現加減乘除。給的四個例子。數字只有0-9,運算只有加減乘除,而且每個運算只有一個操作符。(可以先不看下面,自己先想一下怎麼寫)

  首先,每一個例子都是同樣的結構---類名和四個方法。拿第一個例子來舉例,ruby中調用一般都是 對象.方法的形式。那麼初步的思路就是Calc類構建一個new方法(當然調用new的時候會自動調用initialize方法,如果只是返回一個執行個體對象,不用寫這個方法),為Calc.new對象構建一個one方法,為Calc.new.one對象構建一個plus方法,為Calc.new.one.plus對象構建一個two方法。

    這樣用單例方法好像沒有什麼問題,雖然可能會複雜一些,但是應該是能做出來的。那怎麼寫呢?(其實我也不知道,要是有思路求指教)

    我的思路是類似下面的,請看代碼

 

 1 class A 2     def one 3         def self.plus 4             def self.one 5                 p "one+plus+one" 6             end 7             self 8         end 9         self10     end11 end

 

    現在的問題就是把方法名用變數來代替,但是這樣的話參數怎麼傳進去呢?這就是個問題了。於是這種想法就擱淺了。

   關於方法嵌套定義的問題,參見http://blog.csdn.net/kiwi_coder/article/details/8122085,講的很清楚。

 

    一種方法不通就是另一種方法了。在上一種方法中,由於我忘記傳回值為self。因此經常出現nil沒有方法的錯誤。於是就想到了method_missing。ruby中的method_missing就是在這個對象沒有某個方法的時候,會到method_missing中去找解決方案。method_missing方法正好是把方法名當成參數,於是就可以直接調用了。

代碼如下:

 1 class Calc 2   # Implement here 3  @@str="" 4  @@time = 0  5  def method_missing(name) 6    has = { :one => 1,:two=>2,:three => 3,:four=>4,:five => 5, 7      :six=>6,:seven => 7,:eight=>8,:nine => 9,:zero=>0,} 8    9    mth ={:plus=>"+",:minus=>"-",:times=>"*",:divided_by=>"/"} 10    @@str = "" if @@time == 311    @@str << has[name].to_s if has.has_key?(name)12    @@str << mth[name] if mth.has_key?(name)13    @@time += 114    @@time -= 3 if @@time > 315    if @@time == 3 16      eval @@str 17    else18      self19    end  20  end21 end

把方法名傳入method_missing的時候,先定義兩個hash,然後把方法名對應的值寫到一個類變數字串@@str中,最後用eval執行字串。@@time是用來計算方法個數,每進行一個運算,字串清空。值得注意的是:如果不執行的時候,要返回self。

這段代碼是我提交的代碼,僅僅是完成了功能,但是寫的不好。

不足之處:

1使用了eval,這個方法是各種書中不推薦的

2其實兩個hash可以合并,這個問題不大。

3我的這個方法只是把方法名合并成字串,有點投機取巧,而且不能適合更多的運算。

 

 

提交之後,看了別人的代碼。拿出一個推薦最多的和大家分享。

代碼如下:

 1 # Chainable: 2 # Calc.new.one.plus.one.plus.one == 3 3  4 class Fixnum 5   def plus;       Calc.new("+", self) end 6   def minus;      Calc.new("-", self) end 7   def times;      Calc.new("*", self) end 8   def divided_by; Calc.new("/", self) end 9 end10 11 class Calc12   def initialize(*arguments)13     if arguments.length == 214       @operation = arguments[0]15       @number    = arguments[1]16     end17   end18   19   %w(zero one two three four five six seven eight nine).each_with_index do |w,i|20     define_method(w) { perform i }21   end22   23   def perform number24     if @operation25       @number.send(@operation, number)26     else27       number28     end29   end30 end

簡單分析一下,4-9行在Fixnum類中定義了加減乘除,並且返回Calc的對象,帶著兩個參數。12-17行是初始化過程。19-21行定義了0-9的對應方法,每個方法內容都是執行perform方法。23-29行定義了perform方法。拿Calc.new.one.plus.two來解釋,Calc.new,不帶參數,所以返回Calc的一個執行個體對象。Calc.new.one,調用執行個體方法one,

執行perform 1,此時@operation沒有值,因此返回number的值1。Calc.new.one.plus,1是Fixnum類的執行個體,調用plus方法,返回了一個Calc.new的對象,並且帶有兩個參數。因此給@operation和@number分別賦值為‘+‘,1(這裡的self就是1)。Calc.new對象又調用two方法,此時有了@operation,因此執行if條件陳述式裡的內容,得到結果3。

這種方法還可以執行更長的方法,例如Calc.new.one.plus.two.minus.three。

 

總結一下:鏈式訪問要把每一個方法的對象都弄清楚,每一個方法的傳回值是下一個方法的對象。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.