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

方法重复

引用书上的一个例子,有一个报价系统,你需要从数据库中读取各种仪器设备的信息、价格,比如购买一台电脑,需要读取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. SQL Server 2017 安装过程中的一点说明(有点意思)

    会提到:“安装程序无法与下载服务器联系.请提供 Microsoft 机器学习服务器安装文件的位置,然后单击“下一步”.可从以下位置下载安装文件” 的解决方案 安装过程和2016大体一致,机器学习这款更 ...

  2. bootstrap validator 使用 带代码

    如何使用bootstrapVlidator插件? 下载bootstrapVlidator插件 在需要使用的页面引入bootstrapVlidator的js文件和css文件 如: 注: 在此基础之前必须 ...

  3. ASP.NET Core远程调试

    关于ASP.NET Core远程调试的具体做法可参考微软文档——Remote Debug ASP.NET Core on a Remote IIS Computer in Visual Studio ...

  4. 【NOIP2012提高组】同余方程

    https://www.luogu.org/problem/show?pid=1082 方程可化为ax+by=1. 用扩展欧几里得算法得到ax'+by'=gcd(a,b)的一组解后,可得x=x'/gc ...

  5. kubernetes nginx ingress 使用记录

    前言 ingress是一种可以暴露k8s集群内部service的方式,用户编辑配置文件定义一个ingress资源即可实现外部网络访问内网service. ingress controller是来管理所 ...

  6. Java IO(3)非阻塞式输入输出(NIO)

    在上篇<Java IO(2)阻塞式输入输出(BIO)>的末尾谈到了什么是阻塞式输入输出,通过Socket编程对其有了大致了解.现在再重新回顾梳理一下,对于只有一个“客户端”和一个“服务器端 ...

  7. KMP算法具体解释

    这几天学习kmp算法,解决字符串的匹配问题.開始的时候都是用到BF算法,(BF(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配 ...

  8. HTML学习笔记之三(localstorage的使用)

    localstorage的使用 1.获取对象 var localstroage = window.localStorage; 2.存储值 localstroage.setItem('openid',' ...

  9. Docker 搭建 etcd 集群

    阅读目录: 主机安装 集群搭建 API 操作 API 说明和 etcdctl 命令说明 etcd 是 CoreOS 团队发起的一个开源项目(Go 语言,其实很多这类项目都是 Go 语言实现的,只能说很 ...

  10. 超详细的 Linux CentOS yum 源的配置与使用【转发+新增】

    一.yum 简介 yum,是Yellow dog Updater, Modified 的简称,是杜克大学为了提高RPM 软件包安装性而开发的一种软件包管理器.起初是由yellow dog 这一发行版的 ...