Ruby元编程 第三章 方法

动态方法

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

obj = MyClass.new
obj.send(:my_method, 3) #=> 6

在send方法里,想调用的方法名变成了参数,这样就可以在代码运行的最后一刻决定调用哪个方法。称之为动态派发

例如项目中使用的 order_trades_json 方法

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

class MyClass
  private def private_method
    puts "private_method"
  end
end
obj = MyClass.new
obj.send(:private_method) #=> private_method

你可以使用send调用任何方法,包括私有方法

如果你不喜欢这种行为,可以使用public_send

send方法的参数既可以是string也可以使symbol

string和symbol

1.相同的symbol是一个对象,相同的string并不一定是一个对象

"dog".equal?("dog")  #=> false 
:dog.equal?(:dog)    #=> true

2.处理符号相比string,占用更少的资源 ,性能更优

因为字符串变量必须具有各种修改其内容的功能,所以字符串的维护和处理的开销就很大。但是有些时候,我们并不需要修改和处理创建的文本信息,这个时候就应该用符号,减少资源开销。

动态定义方法
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

用define_method方法代替def关键字定义方法的一个重要原因是
define_method方法允许在运行时决定方法的名字。

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

method_missing

method_missing方法是BasicObject的一个私有实例方法,当ruby在类中任何地方都找不到某个方法时候,会最终调用它。它会抛出一个NoMethodError进行响应

class MyClass
  def my_method
  end
end

obj = MyClass.new
obj.my_method2 # => undefined method `my_method2' for #<MyClass:0x00007f8c098bbf18> (NoMethodError)

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

Mash是一个类似哈希表的对象,它的属性就像是普通的Ruby的变量。如果想添加一个新的属性,只要给这个属性添加一个值即可

iceream = Hashie::Mash.new
iceream.flavor = "strawberry"
iceream.flavor # => "strawberry"
module Hashie
  class Mash < Hashie::Hash
    def method_missing(method_name, *args, &blk)
      return self.[](method_name, &blk) if key?(method_name)
      match = method_name.to_s.match(/(.*?)([?=!]?)/)
      case match[2]
      when "="
        self[mathc[1]] = args.first
        #   ...
      else
        default(method_name, *args, &blk)
      end
    end
    
    #   ...
  end
end

如果方法名字存在,那么调用 [] 方法返回相应的值,如果方法名以=结尾,那么method_missing会去掉末尾的=,把余下的部分作为属性,用哈希表相应的键值对存储该属性。

const_missing

还有一个const_missing方法,作用跟method_missing类似,只是处理的是常量找不到的问题。如Rake中为兼容而允许在后续版本中使用先前没有命名空间的老名字,就是这么实现的

class Module
    def const_missing?(const_name)
        case const_name
        when :Task
            Rake.application.const_warning(const_name)
            Rake::Task
        when :FileTask
            Rake.application.const_warning(const_name)
            Rake:: FileTask
        when :FileCreationTask
            #...
    end
end

白板类

如果不特别指定超类,创建的类默认继承自Object类
当幽灵方法和真实方法发生名字冲突,幽灵方法就会被忽略
比如Object#display方法,如果你不需要那个继承来的方法,可以考虑继承白板类,或者删除它们
Ruby为你提供了一个白板类

根类BasicObject只有很少的几个实例方法

BasicObject.instance_methods # => [:!, :==, :!=, :__send__, :equal?, :instance_eval, :instance_exec, :__id__]
删除方法

某些情况你可能还要删除某些方法
这时候可以使用
Module#undef_method
或者Module#remove_method
前者会删除包括继承而来的所有方法,而后者只会删除接收者自己的方法,而保留继承的方法。

小结

大多数情况下,幽灵方法都不如动态方法来得好,因为它并不是真正的方法,而只是类似异常的一个功能,使用它会导致诸如难以调试、方法被定义等问题。在能使用动态方法完成需求的场景下,我们都应该优先考虑动态方法而不是幽灵方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值