• 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



    研究的不好,有错误大家交流!
  • 相关阅读:
    Flink资料(5) -- Job和调度
    Flink资料(4) -- 类型抽取和序列化
    Flink资料(3)-- Flink一般架构和处理模型
    Flink资料(2)-- 数据流容错机制
    Flink资料(1)-- Flink基础概念(Basic Concept)
    联系InfoSphere Streams和OpenMI时对水利模型联系的设计模式的一些考虑
    [Azure][CLI][02]Basic OPS
    [Azure][PowerShell][ARM][01]Connect
    [Azure][PowerShell][ASM][13]Reset Password
    [Azure][PowerShell][ASM][12]ACL
  • 原文地址:https://www.cnblogs.com/IAmBetter/p/2963696.html
Copyright © 2020-2023  润新知