美文网首页
元编程-类定义

元编程-类定义

作者: 葫芦葫芦快显灵 | 来源:发表于2019-07-09 22:26 被阅读0次

    类定义

    注意: 类也是对象

    当前类

    • 在程序顶层,当前类为main对象的类 Object
    • class 打开一个类时(或者打开一个module),打开的类即当前类
    • 在一个方法中,当前类即当前对象的类
                            # 顶层的类为Object,若在此定义方法则为Object的实例方法
        class MyClass       # class 打开的MyClass 即为当前类
           def my_method    # MyClass为当前类
                
           end
        end
    

    class_eval 方法

    class 限制: 需要知道类名
    class_eval 不需要知道类名就能打开当前类

    Module#class_eval会在已存在类的上下文中执行一个块

        def add_method_to a_class               # 此时当前类为Object
          a_class.class_eval do                 # 当前类变更 a_class
            def test_a
                'class_eval会修改当前类和self'
            end
          end
        end
        
        add_method_to String
        "a".test_a  # => 'class_eval会修改当前类和self'
    

    对比:
    class:

    1. 打开类需要指定类的名字,而且必须时常量
    2. class 是作用域门,使用class会失去局部绑定
      Module#class_eval:
    3. 任何代表类的变量都可以使用class_eval
    4. class_eval使用的是代码块,扁平作用域,可以获取局部绑定

    单例方法

    ruby 允许给单个对象增加一个方法
    只对单个对象生效的方法-单例方法

    str = 'this is a singleton_method'
    
    def str.title?
      str.update == str
    end
    
    str.title? # => false
    str.methods.grep(/title?/) #=> [:title?]
    str.singleton_methods      #=> [:title?]
    

    这一段代码单独为str添加一个title? 方法,其他的对象是没有这个方法的

    单例方法也可以用Object#define_singleton_method 来定义

    类方法

    类也是一个对象
    类名只是常量

    an_obj.a_method
    AClass.a_class_method
    

    类方法的调用和对象实例方法的调用语法是一样的,所以类方法的实质就是: 类方法是一个类的单例方法

    类宏

    attr_accessor 是一个类(Module类)的类方法
    当一个模块引入这个模块的时候自动帮我们拓展出这个方法
    示例: ruby 内核中的方法 attr_accessor

     class MyClass
        def my_attribute=(value)
          @my_attribute = value
        end
        
        def my_attribute
          @my_attribute
        end
     end
     
     obj = MyClass.new
     obj.my_attribute= 'whj'
     obj.my_attribute # => 'whj'
    
    

    可以用 Module#attr_*来定义访问器

    所有的attr_* 方法都定义在Module中,不管self是类还是模块,都可以使用方法,像这样的方法称之为类宏

    单件类(元类/本征类)

    一个对象的单例方法没有存在obj中,因为obj不是一个类,也没有存在obj的类中,因为这样obj类的所有实例都能共享这个单例方法

    单件类是一个对象特有的隐藏类
    Object#class 会将元类隐藏起来

    如何进入单件类:

    1. class的特需语法
    class << an_obj
        #do_something
    end
    

    如果想要获得单件类的引用,需在离开作用域时返回self

    obj = Object.new
    singleton_class = class < obj
      self
    end
    singleton_class.class # => Class
    
    1. Object#singleton_class 能够获取单件类的引用

    单件类是对象的单件方法存放的地方
    每个单件类只有一个实例,而且不能被继承

    单件类和模块结合

    类扩展

    一个class 引入一个module时,只引入了module的实例方法,不会引入类方法
    解决:
    将类方法当初一个普通的实例方法,然后在class的单例类中引入这个module-类扩展

    module MyModule
     def a_method
        "hello, whj"
     end
    end
    
    class MyClass
      class << self
        include MyModule
      end
    end
    
    MyClass.a_method # => 'hello, whj'
    

    对象扩展

    module MyModule
     def a_method
        "hello, whj"
     end
    end
    
    class MyClass
     
    end
    
    obj = MyClass.new
    class << obj
        include MyModule
    end
    
    obj.a_method # => 'hello, whj'
    

    方法包装器

    包(GEM)中的方法不能直接修改,希望能够为这个方法附加一个额外的属性, 所有的客户端都会自动获得这个属性

    Module#alias_method 别名

    class MyClass
        def my_method
            'hello, whj'
        end
    end
    
    alias_method :m, :my_method
    
    obj = MyClass.new
    obj.my_nethod # => 'hello, whj'
    obj.m         # => 'hello, whj'
    

    环绕别名

    1. 给方法重定义一个别名
    2. 重定义这个方法
    3. 在新的方法中调用老的方法

    细化包装器

    下包含包装器 Module#prepend (较常用)

    prepend包含的模块会插入该类祖先链的下方, 意味着它可以重写该类的同名方法

    class MyClass
      def my_method
        "a"
      end
    end
    
    module MyModule
      def my_method
        "b"                     #也可以使用super 来继承
      end
    end
    
    MyClass.class_eval do 
        prepend MyModule
    end
    
    obj = MyClass.new
    obj.my_method # => "b"
    
    

    相关文章

      网友评论

          本文标题:元编程-类定义

          本文链接:https://www.haomeiwen.com/subject/evlqkctx.html