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

元编程:类定义

作者: Jayzen | 来源:发表于2016-01-18 21:25 被阅读28次
    1.类定义和当前类
    1.在类定义中,当前对象self就是正在定义的类,当前类就是self就是正在定义的类。
    2.如果有一个类的引用,则可以用class_eval()方法打开这个类。
    def add_method_to(a_class)
      a_class.class_eval do
      #class_eval的别名是module_eval
        def m
          puts "hello"
        end
      end
    end
    
    add_method_to String
    "abc".m  #=>"hello"
    
    3.方法中定义方法
    class MyClass
      def method_one
        def method_two
          puts "hello"
        end
      end
    end
    
    obj = MyClass.new
    obj.method_one #调用method_one,定义method_two
    obj.method_two
    
    2.类实例变量
    1.所有的实例变量属于当前self,属于当前类的实例变量是类实例变量
    2.类实例变量只能被类本身所访问,而不能被类的实例或者子类所访问
    
    class MyClass
      @my_var = 1
    
      def self.read
        @my_var
      end
    
      def write
        @my_var = 2
      end
    
      def read
        @my_var
      end
    end
    
    obj = MyClass.new
    obj.write
    puts obj.read #>2
    puts MyClass.read #>1
    #访问这个变量不是说通过这个类或者类的对象直接调用这个变量
    MyClass.my_var  #=>undefined method my_var
    #而是通过调用方法的形式调用这些变量,代码如下所示:
    obj.read #>2
    MyClass.read #>1
    
    3.类变量
    1.和类实例变量不同,类变量可以被子类或者类的实例所使用
    2.类变量不属于真正的类,他们属于类体系结构
    
    class MyClass
      @@my = 1
    
      def self.read
        @@my_var
      end
    
      def write
        @@my_var = 2
      end
    
      def read
        @@my_var
      end
    end
    
    class SonClass < MyClass
    end
    
    son_obj = SonClass.new
    puts son_obj.read  #=>1
    obj = MyClass.new
    obj.write
    puts obj.read #=>2
    puts MyClass.read #=>2
    
    #下面的代码说明类变量不属于真正的类,他们属于类体系结构。
    @@v = 1
    class MyClass
      @@v = 2
    end
    
    puts @@v #=>2  
    #warning class variable access from toplevel
    # @@v定义于main的上下文,它属于main的类Object,所以也属于Object的所有后代
    
    4.使用Class定义类
    #定义一个Array的子类:
    class MyClass < Array
      def my_method
        puts "hello"
      end
    end
    
    #不使用class关键词定义Array的子类:
    c = Class.new(Array) do
      def my_method
        puts "hello"
      end
    end
    
    MyClass = c
    puts c.name  #=>MyClass
    
    #类是匿名类,类名其实是常量,如下的形式给类进行赋值:
    MyClass = c
    #从最后一句可以知道c.name是这个类的名字。
    
    #其实直接给类进行常量赋值也是可以的,见如下的代码:
    MyClass = Class.new(Array) do
      def my_method
        puts "hello"
      end
    end
    
    obj = MyClass.new
    obj.my_method
    
    5.单件方法
    1.针对单个对象生效的方法叫做单件方法,类方法也是单件方法,类也是对象
    
    #如下代码是字符串对象生成单件方法:
    str = "just a regular string"
    
    def str.title?
      self.upcase ==self
    end
    
    #类方法的三种形式
    class MyClass
      def MyClass.method_one
        puts "this is the method_one"
      end
    
      def self.method_two
        puts "this is the method_two"
      end
    
      class << self
        def method_three
          puts "this is the method_three"
        end
      end
    end
    
    6.类宏
    1.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 = "x"
    puts obj.my_attribute #=>"x"
    
    #上面的代码的简化形式
    class MyClass
      attr_accessor :my_attribute
      #定义两个方法和一个实例变量
    end
    
    obj = MyClass.new
    obj.my_attribute = "x"
    puts obj.my_attribute  #=>"x"
    
    #类宏进行应用
    class Book
      def title
        puts "this is the title"
      end
    
      def self.deprecate(old_method, new_method)
        define_method(old_method) do |*args, &block|
          warn "Warning :#{old_method}() is deprecated, use #{new_method}()"
          send(new_method, *args, &block)
        end
      end
    
      deprecate :GetTitle, :title #调用和定义方法
    end
    
    book = Book.new
    book.GetTitle  #=>结果为预期所示
    
    7.单件类
    1.为了补全对象模型的知识,找到单件方法的藏身之所。
    2.我们称单件方法所在的类为单件类。
    3.单件类是一个特殊的类,它只有一个实例,并且不能被继承。
    4.一个对象的单件类的父类是这个对象的类。
    5.一个类的单件类的超类是这个类的超类的单件类。
    
    #获得eigenclass:
    obj =  Object.new
    eigenclass = class << obj
      self
    end
    #通过class << obj的形式可以进入obj单件类的领域中
    #这里的self对象就是单件类,整个返回的就是一个单件类
    puts eigenclass.class #=>Class
    
    
    #为了方便查找对象的eigenclass,在Object类中定义了如下的代码:
    class Object
      def eigenclass
        class << self
          self
        end
      end
    end
    
    #任何类(除了BasicObject)都是继承于Object,因此此方法eigenclass能适用于所有的对象
    #任何对象调用eigenclass方法,返回的都是该对象的单件类。
    
    #对象单件方法表示形式:
    obj = Object.new
    class << obj
      def a_singleton_method
        puts "this is the obj singleton method"
      end
    end
    
    obj.a_singleton_method #=>this is the obj singleton method
    
    #演示如何寻找单件类的父类:
    class Object
      def eigenclass
        class << self
          self
        end
      end
    end
    
    class C
      def a_method
        puts "this is the class C method"
      end
    end
    
    class D < C
    end
    
    obj = D.new
    obj.a_method
    
    class << obj
      def a_singleton_method
        puts "this is the singleton method"
      end
    end
    
    #对象单件类的父类是该对象的类
    obj.eigenclass.superclass #=>D
    
    对象模型查找方法补充:
    1.对象有eigenclass,从这个eigenclass类中开始查找方法。
    2.在eigenclass类中找不到方法,那么它会沿着祖先链向上来到eigenclass的超类。
    
    class Object
      def eigenclass
        class << self
          self
        end
      end
    end
    
    class C
      class << self
        def a_class_method
          puts "C.a_class_method"
        end
      end
    end
    
    class D < C
    end
    
    obj = D.new
    obj.a_method
    
    C.eigenclass  #=>#<Class:C>
    D.eigenclass  #=>#<Class:D>
    D.eigenclass.superclass #=>#<Class:C>
    C.eigenclass.superclass  #=>#<Class:Object>
    
    结论:类的单件类的父类是其类的父类的单件类
    
    #D(D类的eigenclass)的超类是#C,#C的超类是#Object,于是可以在子类调用父类的类方法
    D.a_class_method #=>"C.a_class_method"
    
    8.类属性
    1.对象属性就是通过对象调用方法来达到访问属性的目的
    2.类属性就是直接通过类名直接调用属性的方式
    class MyClass
      attr_accessor :a
    end
    
    obj = MyClass.new
    obj.a = 2
    abj.a  #=>2
    
    class MyClass
    end
    
    class Class
      attr_accessor :b
    end
    
    MyClass.b = 42
    MyClass.b #=> 42
    
    1.类MyClass是类Class的对象,因此类MyClass可以直接调用类Class的实例方法,
    2.如果是专属于MyClass的属性,需要另外一种技术,是添加类方法的另外一种形式:
    
    class MyClass
      #打开eigenclass域,定义类方法,通过类宏的形式,可以获得类的属性
      class << self
        attr_accessor :c
      end
    end
    
    MyClass.c = "this is class singleton attribute"
    MyClass.c #=>"this is class singleton attribute"
    
    9.类扩展和对象扩展
    1.类中include一个具有模块方法的模块,该方法是该类的类方法,也是该类单件类的实例方法,这种技术叫类扩展。
    2.将上面的类扩展应用到任意对象上,叫做对象扩展。
    
    #当类包含模块时,获得的是该模块的实例方法,而不是类方法
    #而模块中的类方法存在于模块的eigenclass中,无法触碰。
    module MyModule
      def self.my_method
        puts "hello"
      end
    end
    
    class MyClass
      include MyModule
    end
    
    MyClass.my_method  #NoMethodError!
    
    #将模块引入到类的eigenclass中,这样子类就可以将模块中的实例方法作为类方法引入:
    module MyModule
      def my_method
        puts "hello"
      end
    end
    
    class MyClass
      class << self
        include MyModule
      end
    end
    
    MyClass.my_method  #=>hello
    
    #上面的技术是类扩展,应用到任意对象上是对象扩展
    module MyModule
      def my_method
        puts "hello"
      end
    end
    
    obj = Object.new
    class << obj
        include MyModule
    end
    
    obj.my_method  #=>hello
    obj.singleton_methods #=>[:my_method]
    
    #使用Object#extend方法也可以实现类扩展和对象扩展
    module MyModule
      def my_method
        puts "hello"
      end
    end
    
    obj = Object.new
    obj.extend MyModule
    obj.my_method  #=>hello
    
    class MyClass
      #是self.extend的省略形式
      extend MyModule
    end
    MyClass.my_method #=>hello
    
    #extend是Object类的方法,所以对象obj可以调用该方法
    #MyClass可以直接调用extend方法,MyClass是Class类的对象,而Class类的祖先链包括Object,在类中可以直接使用该类的类方法:
    class MyClass
      def MyClass.class_method
        puts "this is the class method"
      end
    
      class_method  #=>this is the class method
    end
    
    10.方法包装器:别名
    作用:有一个不能直接修改的方法,因为这个方法在库中,希望这个方法包装额外的特性,所有的客户端都能自动获取这个额外特性。
    环绕别名:
    1.给方法定义一个别名
    2.重定义这个方法
    3.在新的方法中调用老的方法
    
    #使用关键字alias:
    class MyClass
      def my_method
        puts "this is my method"
      end
    
      alias :m :my_method  #关键字alias,不用加逗号
    end
    
    obj = MyClass.new
    obj.my_method  #=> this is my method
    obj.m  #=> this is my method
    
    #使用alias_method方法
    class MyClass
      alias_method :m2, :m
    end
    
    obj.m2 #=> this is my method
    
    #环绕别名
    class String
      alias :real_length :length
    
      def length
        real_length > 5 ? "long" : "short"
      end
    end
    
    "war and peace".length #=> long
    "war and peace".real_length #=> 13
    
    11.方法包装器:细化封装器
    #细化中调用super方法,则会调用那个没有细化的原始方法
    module StringRefinement
      refine String do
        def length
          super > 5 ? 'long' : 'short'
        end
      end
    end
    
    using StringRefinement
    "war and peace".length  #=>"long"
    
    12.方法包装器:下包含包装器
    #使用module#prepend方法,会把模块插入到祖先链到该类的下方,而非上方
    #通过super调用该类中的原始方法
    module ExplicitString
      def length
        super > 5 ? 'long' : 'short'
      end
    end
    
    String.class_eval do
      prepend ExplicitString
    end
    
    "war and peace".length  #=>'long'
    

    相关文章

      网友评论

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

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