ruby元編程 那些書裡沒有的知識 define_method

來源:互聯網
上載者:User
你有多少種方式建立一個方法?大多數人想到的可能是def 關鍵字 Ruby代碼  
  1. #普通方法   
  2. def tele_you   
  3.     puts "I am Anleb"  
  4. end  
#普通方法def tele_you    puts "I am Anleb"end
Ruby代碼  
  1. #定義單件方法   
  2. n="Anleb"  
  3. def n.tell_you   
  4.     puts "I am #{self}"  
  5. end  
  6. n.tell_you  
#定義單件方法n="Anleb"def n.tell_you    puts "I am #{self}"endn.tell_you

Ruby代碼  

  1. #define_method   
  2. class Project   
  3.     define_method :tell_you do |name|   
  4.         puts name   
  5.     end  
  6. end  
  7.   
  8. a=Project.new  
  9. a.tell_you("Anleb")  
#define_methodclass Project    define_method :tell_you do |name|        puts name    endenda=Project.newa.tell_you("Anleb")

具體分析下:define_method方法 Ruby代碼  

  1. Kernel.private_methods.include?("define_method")  #true  
Kernel.private_methods.include?("define_method")  #true

可以看到define_method是一個私人方法,那麼私人方法調用是有規定的:
1.不能有顯式調用,也就是不能有接受者,不能self.define_method這樣調用
2.私人方法是可以被繼承的
3.私人方法可以被send強制調用,如:send(:private_method)
4.只能在自身中調用私人方法(體會下這句話的意思)

上面Project類中,當前self是類Project,然後隱式調用define_method方法建立方法

define_methods動態建立方法,什麼是動態建立呢,就是代碼運行時就建立定義了方法,利用動態建立和動態派發可以實現ruby的代碼重構,這是魔法!
例子元編程書上有,中文版 46頁,英文版69頁

看一個例子:

  1. class Project1   
  2.     define_method :tell_you do |name|   
  3.         puts name   
  4.     end  
  5. end  
  6.   
  7. class Project2 < Project1   
  8.        
  9. end  
  10.   
  11. a=Project2.new  
  12. a.tell_you("Anleb")   
  13. Project1.instance_methods(false) #["tell_you"]  
class Project1    define_method :tell_you do |name|        puts name    endendclass Project2 < Project1    enda=Project2.newa.tell_you("Anleb")Project1.instance_methods(false) #["tell_you"]

1.說明define_method定義的方法和def定義沒區別,都可以被繼承
2.define_method的方法是存在於類中的執行個體方法

修改代碼: Ruby代碼  

  1. class Project1   
  2.     define_method :tell_you do |name|   
  3.         puts name   
  4.     end  
  5.   
  6.     def creat_method   
  7.         define_method :new_method do    
  8.             puts "this is a new method"  
  9.         end  
  10.     end  
  11. end  
  12. Project1.new.creat_method   
  13.   
  14.   
  15. Error:test.rb:7:in `creat_method': undefined method `define_method' for #<Project1:0x2bc7008> (NoMethodError)  
class Project1    define_method :tell_you do |name|        puts name    end    def creat_method        define_method :new_method do             puts "this is a new method"        end    endendProject1.new.creat_methodError:test.rb:7:in `creat_method': undefined method `define_method' for #<Project1:0x2bc7008> (NoMethodError)

一拍腦袋,額,忘記說了,define_method是Object Class方法,也就是只有類才可以調用,
creat_method的當前self肯定是一個對象啊,對象不是類,所以不能調用,修改代碼

  1. def creat_method   
  2.        self.class.define_method :new_method do    
  3.            puts "this is a new method"  
  4.        end  
  5.    end  
 def creat_method        self.class.define_method :new_method do             puts "this is a new method"        end    end

調用方法:

  1. Project1.new.creat_method   
  2. Error:test.rb:7:in `creat_method': private method `define_method' called for Project1:Class (NoMethodError)  
Project1.new.creat_methodError:test.rb:7:in `creat_method': private method `define_method' called for Project1:Class (NoMethodError)

崩潰了,怎麼還不行,看看提示,說這是一個私人方法,額。。。忘記了,private方法不能顯式有接受者,我們想到一個辦法,對,那就是send方法

修改代碼:

  1. class Project1   
  2.     define_method :tell_you do |name|   
  3.         puts name   
  4.     end  
  5.   
  6.     def creat_method   
  7.         self.class.send(:define_method,:new_method) do    
  8.             puts "this is a new method"  
  9.         end  
  10.     end  
  11. end  
  12.   
  13. a=Project1.new  
  14. p Project1.instance_methods(false) #["creat_method", "tell_you"]   
  15. a.creat_method   
  16. p Project1.instance_methods(false) #["creat_method", "tell_you"]  
class Project1    define_method :tell_you do |name|        puts name    end    def creat_method        self.class.send(:define_method,:new_method) do             puts "this is a new method"        end    endenda=Project1.newp Project1.instance_methods(false) #["creat_method", "tell_you"]a.creat_methodp Project1.instance_methods(false) #["creat_method", "tell_you"]

終於成功了,這種技術叫做 動態派發技術,常用在Method_messing方法。

解法2: Java代碼  

  1. class Project1   
  2.     define_method :tell_you do |name|   
  3.         puts name   
  4.     end   
  5.   
  6.     def self.creat_method   
  7.         define_method :new_method do  #當前self是類,所以可以調用,並且隱式   
  8.             puts "this is a new method"  
  9.         end   
  10.     end   
  11.     creat_method   
  12. end   
  13.   
  14. Project1.new.new_method  
class Project1    define_method :tell_you do |name|        puts name    end    def self.creat_method        define_method :new_method do  #當前self是類,所以可以調用,並且隱式            puts "this is a new method"        end    end    creat_methodendProject1.new.new_method

解法3: Ruby代碼  

  1. class Project1   
  2.     class << self  
  3.         def creat_method   
  4.         define_method :new_method do  #當前self是類   
  5.             puts "this is a new method"  
  6.         end  
  7.     end  
  8.     end  
  9.     creat_method   
  10. end  
  11.   
  12. Project1.new.new_method  
class Project1    class << self        def creat_method        define_method :new_method do  #當前self是類            puts "this is a new method"        end    end    end    creat_methodendProject1.new.new_method

研究的不好,有錯誤大家交流!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.