作为一个动态语言,对象中的方法不会像静态语言一样需要验证确实存在,动态语言的对象之间一直保持着交谈,如果你调用一个不曾定义过的方法,程序也不会马上就报错而无法运行,只有当运行到你调用这个方法时,解释器会由于找不到该方法而无法继续解释。而在这之前,你可以在运行的过程中添加该方法。你甚至可以用一个方法来处理所有不曾定义过的方法,而做出某些反应。

方法重复

引用书上的一个例子,有一个报价系统,你需要从数据库中读取各种仪器设备的信息、价格,比如购买一台电脑,需要读取cpu、鼠标、键盘等信息。你可能需要一个mouse()方法来读取鼠标的型号以及价格,一个cpu()方法来读取cpu的型号以及价格,一个keyboard()方法来读取键盘型号以及价格等等。这些方法的内容都是类似的,都是从数据库中执行相应的检索语句,但是检索语句却又不同,这种相似却不一样的重复代码会让整个程序看起来非常的不cool,从原理上,这些方法执行的都是相同的过程,应该要有一种技术消除这些重复代码。

在Ruby中,有两种技术可以完成这项工作:动态方法和幽灵方法。

动态方法

动态创建

在Module类中,有一个define_method的方法,Module#define_method方法可以通过传入的参数和代码块来动态地创建方法:

class Computer
    def self.define_component(name)
        define_method(name){
        puts "getting #{name} info"
        puts "getting #{name} price"
    }
    end
end
Computer.define_component :keyboard
obj = Computer.new
obj.keyboard

如上所示,在Computer中并没有定义keyboard方法,但是可以通过define_method方法,在代码的其他地方动态地创建keyboard方法,也可以Computer.define_component:cpu,创建一个cpu的方法。 

动态调用

完成了动态创建的工作,接下来就要实现动态调用。Ruby在Object类中,封装了一个send方法,Object#send方法通过传入的参数来调用相应的方法。在每一个设备的方法中,调用的查询语句是不一样的,如keyboard应该调用data_source.get_keyboard_info,data_source.get_keyboard_price等方法,而cpu却需要调用data_source.get_cpu_info,data_source.get_cpu_price方法,通过Object#send方法,就可以实现对这一类方法的调用。如:

obj.send:keyboard

就能调用obj中的keyboard方法,同理可以实现其他方法的动态调用。send同时也可以传入方法参数:obj.send “method_name”,para。

幽灵方法:method_missing()

method_missing()是Kernel模块的一个方法,而所有的对象都继承自Kernel,所以所有的对象都有一个method_missing()方法。

method_missing()方法会在找不到方法的时候调用,并返回一个错误的信息,而通过改写method_missing,可以实现当方法不存在时执行一种统一的操作:

class MyClass
    def method_missing(name)
        puts "getting #{name} info"
        puts "getting #{name} price"
    end
end
obj = MyClass.new
obj.cpu

但是method_missing()却不能随意使用,仔细思考上述代码,其实存在很多问题,比如会调用你不希望调用的一些方法,如pig.fly等,在上述问题中,如果数据库中并没有一些数据,比如,book,如果使用幽灵方法来调用,则会造成错误。所以需要加上respond_to?()方法来确认数据库是否能够正确响应调用的方法;幽灵方法也会因为不加限制而将一些变量也认为是方法,就需要对方法的范围做一个限制;同时,在对象的祖先链中,可能存在一些方法是你期望用幽灵方法解决的,而事实上,因为解释器找到了那个方法,尽管不是你想要的那个方法,但是仍然会执行找到的方法,你就需要删除一些继承来的方法,或者继承BasicObject来清除所有继承来的方法等等。

幽灵方法很cool,但是一定要慎重使用,保守的我看来是更加喜欢用动态方法的方式去解决了。

Ruby学习之动态调用的更多相关文章

  1. Web Service学习笔记:动态调用WebService

    原文:Web Service学习笔记:动态调用WebService 多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我 ...

  2. Ruby学习笔记4: 动态web app的建立

    Ruby学习笔记4: 动态web app的建立 We will first build the Categories page. This page contains topics like Art, ...

  3. Struts2学习四----------动态方法调用

    © 版权声明:本文为博主原创文章,转载请注明出处 Struts2动态方法调用 - 默认:默认执行方法中的execute方法,若指定类中没有该方法,默认返回success <package nam ...

  4. Ruby学习之mixin

    直接上代码: module Action def jump @distance = rand(4) + 2 puts "I jumped forward #{@distance} feet! ...

  5. .NET简谈反射(动态调用)

    我们继续C#基础知识的学习,这篇文章主要要讲的是我们C#程序员迈向高级C#程序员的关键性的一步. 有的朋友会说事实不是这样的,我不用反射就不能开发吗?当然可以,但是用与不用肯定是不一样的,任何复杂抽象 ...

  6. WCF入门及在WinForm中动态调用

    一.WCF入门 1. 新建立空白解决方案,并在解决方案中新建项目,项目类型为:WCF服务应用程序,删除系统生成的两个文件IService1.cs与Service1.svc, 添加自定义的WCF[服务文 ...

  7. 使用接口的方式调用远程服务 ------ 利用动态调用服务,实现.net下类似Dubbo的玩法。

    分布式微服务现在成为了很多公司架构首先项,据我了解,很多java公司架构都是 Maven+Dubbo+Zookeeper基础上扩展的. Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按 ...

  8. c/c++ 继承与多态 静态调用与动态调用

    静态调用,与动态调用. 动态调用条件:必须用父类的引用或者指针,并且调用的必须是虚方法. #include <iostream> class Base{ public: virtual i ...

  9. 采用异步来实现重新连接服务器或者重新启动服务 C#中类的属性的获取 SignalR2简易数据看板演示 C#动态调用泛型类、泛型方法 asp .net core Get raw request. 从壹开始前后端分离[.NetCore 不定期更新] 38 ║自动初始化数据库

    采用异步来实现重新连接服务器或者重新启动服务 开启异步监听,不会导致主线程的堵塞,在服务异常断开后一直检测重新连接服务,成功连接服务后通知各个注册的客户端! #region 检测断线并重连OPC服务 ...

随机推荐

  1. CCF-201412-3-集合竞价

    问题描述 试题编号: 201412-3 试题名称: 集合竞价 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 某股票交易所请你编写一个程序,根据开盘前客户提交的订单来确定某特定 ...

  2. iOS中常见的锁

    多线程的安全隐患 一块资源可能会被多个线程共享,也就是说多个线程可能会访问同一块资源. 比如多个线程同时操作同一个对象,同一个变量. 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题. 比 ...

  3. 安装phpnow服务[Apache_pn]提示失败的解决方法

    win 7/win 8/Win10 phpnow提示"安装服务[Apache_pn]失败"错误解决办法汇总 常常在安装phpnow的时候,提示"安装服务 [ Apache_pn ] 失败&q ...

  4. C#线程等待句柄

    相互排斥对象 Mutex private Mutex m = new Mutex(); public void Method(){ m.WaitOne(); //运行操作 m.ReleaseMutex ...

  5. 2014/08/23——OJ及相关站点打开速度非常慢,训练计划login直接error!

    问题: 这个问题存在已经将近一个星期了.刚開始时发现OJ及相关的站点有时候打开有点慢,那时候也没在意,后来时快时慢的越来越频繁:今天早上直接一直都打开非常慢(无论什么时候.这样的情况);训练计划和做题 ...

  6. JIRA 敏捷开发平台部署记录

    1.1 jira说明 JIRA是Atlassian公司出品的项目与事务跟踪工具,被广泛应用于缺陷跟踪.客户服务.需求收集.流程审批.任务跟踪.项目跟踪和敏捷管理等工作领域. JIRA中配置灵活.功能全 ...

  7. 快速序列化组件MessagePack介绍

    简介 MessagePack for C#(MessagePack-CSharp)是用于C#的极速MessagePack序列化程序,比MsgPack-Cli快10倍,与其他所有C#序列化程序相比,具有 ...

  8. 根据实践经验,讲述些学习Java web能少走的弯路,内容摘自java web轻量级开发面试教程

    在和不少比较上进的初级程序员打交道的过程中,我们总结出了一些能帮到合格程序员尽快进阶的经验,从总体上来讲,多学.多实践不吃亏.本文来是从 java web轻量级开发面试教程从摘录的. 1  哪些知识点 ...

  9. path和classpath细节

    从学习java的最初我们就被要求先设置path变量和classpath变量.但是这两个环境变量到底有什么作用呢? 1.path环境变量 path环境变量的主要作用是告诉操作系统到哪里去寻找某个程序,如 ...

  10. docker学习笔记(一)

    docker是一种容器技术,现在火的一塌糊涂,最近公司打算用docker统一开发.测试.预上线.上线环境,所以花了时间研究一下. docker是一种容器技术,之前是基于LXC容器,现在已经改成基于li ...