ruby元编程 那些书里没有的知识 define_method

你有多少种方式创建一个方法?大多数人想到的可能是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}"

end

n.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_method

class Project

    define_method :tell_you do |name|

        puts name

    end

end



a=Project.new

a.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

    end

end



class Project2 < Project1

    

end



a=Project2.new

a.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

    end

end

Project1.new.creat_method





Error: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_method

Error: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_methoddo    
  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

    end

end



a=Project1.new

p Project1.instance_methods(false) #["creat_method", "tell_you"]

a.creat_method

p 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_method

end



Project1.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_method

end



Project1.new.new_method



研究的不好,有错误大家交流!

你可能感兴趣的:(method)