Ruby元编程-学习笔记(二)-方法

动态方法

使用动态方法可以有效的消除重复代码

动态调用方法

class MyClass
    def my_method(arg)
        arg * 2
    end
end

obj = MyClass.new
obj.my_method(3)        # => 6
obj.send(:my_method, 3) # => 6
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

使用.和send都可以调用my_method方法,不过通过send方法可以将调用的放名作为参数,这样就可以在代码运行期间,直到最后一刻才决定调用哪个方法,这种技术被称为动态派发.

同样由于send方法功能的强大,也带来了一些弊端,他会破坏封装性,示例代码如下

class MyClass
    private
    def private_method
        puts "private_method"
    end
end

obj = MyClass.new
obj.private_method          # => 直接调用私有方法会出错
obj.send(:priavet_method)   # => private_method
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

符号

所有能构成合法变量名的字符串前加上:都为符号, 符号和字符串没有关系,他们属于完全不同的类, 他们的区别在于: 符号不可变, 字符串可变,而且一些操作针对符号运算更加快, 符号用于表示事务的名字,尤其是与元编程相关的名字,比如方法名.另外,通过String#to_sym()或String#intern()方法可以把字符串转换为符号,反之使用Symbol#to_s()或Symbol#id2name.

动态定义方法

# 可使用Module#define_method()方法定义一个方法
class MyClass
    def self.define_component(name)
        define_method name do
            puts "define method #{name}"
        end
    end
end

obj = MyClass.new
MyClass.define_component :my_method
obj.my_method       # => define method my_method
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

define_method方法是类方法,只有类才能调用,也是私有方法 
1.不能有显式调用,也就是不能有接受者,不能self.define_method这样调用 
2.可以通过send(:define_method)强制调用

method_missing方法

class MyClass
    def method_missing(method, *args)
        puts "You called: #{method}(#{args.join(', ')})"
        puts "(You also passed it a block)" if block_given?
    end
end

obj = MyClass.new
obj.my_method('a', 'b') {}

=> You called: my_method(a, b)
   (You also passed it a block)
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

method_missing是Kernel的一个实例方法,而所有的对象都继承自Kernel模块, 当调用一个方法时,若在祖先链中未找到该方法,则会调用method_missing方法, Kernel#method_missing()方法会抛出一个NoMethodError进行响应.

幽灵方法

当需要定义很多相似的方法时,可以通过method_missing()方法来方便开发, 使用method_missing方法处理消息,从调用者角度看与普通方法并无差别,但实际上接收者并没有相应的方法,只是统一进行了处理,这被称为幽灵方法.

class MyOpenStruct
    def initialize
        @attributes = {}   # 初始化为哈希
    end
    def method_missing(name, *args)
        attribute = name.to_s
        if attribute =~ /=$/  # 匹配正则,以=结尾
            @attributes[attribute.chop] = args[0]
        else
            @attributes[attribute]
        end
    end
end

obj = MyOpenStruct.new
obj.key = "value"
obj.key     # => "value"
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

上述代码会捕捉obj的调用,并将key或vaule存放在哈希表中. 
注:在性能方面,幽灵方法比普通方法稍慢,因为要查找的路径更长.

动态代理

一个捕获幽灵方法调用并把它们转发给另一个对象的对象,称为动态代理.

class D
    def data_method(text) 
        puts "data_method() => #{text}"
    end
end

class MyClass
    def initialize(data)
        @data = data    
    end
    def method_missing(name)
        @data.send(:data_method, name)  
    end 
end

obj = MyClass.new(D.new)
obj.aabb        # => data_method() => aabb
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

注意:使用method_missing技术后,所有不存在方法的调用都会调用你覆盖的方法,这样会导致一些错误信息(你看不到NoSuchMethod这样的提示了),因此, 在使用method_missing方法的时候,一定要限定其使用范围,并且调用父类的super.method_missing方法,还原错误处理.

const_missing方法

与method_missing方法类似, 当引用一个不存在的常量时,Ruby将把这个常量名作为一个符号传递给const_missing方法.

白板类

当一个幽灵方法和真实方法发生冲突时, 而会执行真实的方法, 这个问题就是动态代理技术的通病, 为了安全起见, 应该在代理类中删除绝大多数继承来的方法, 这就是所谓的白板类. 
- Module#undef_method()方法会删除所有的(包括继承的)方法 
- Module#remove_method()方法只会删除接收者自己的(保留继承的)方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值