Ruby学习之动态调用

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

方法重复

引用书上的一个例子,有一个报价系统,你需要从数据库中读取各种仪器设备的信息、价格,比如购买一台电脑,需要读取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,但是一定要慎重使用,保守的我看来是更加喜欢用动态方法的方式去解决了。

时间: 2024-11-08 21:04:28

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

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

原文:Web Service学习笔记:动态调用WebService 多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我们可能需要在程序运行期间动态调用一个未知的服务.在 .NET Framework 的 System.Web.Services.Description 命名空间中有我们需要的东西. 具体步骤: 1. 从目标 URL 下载 WSDL 数据. 2. 使用 ServiceDescription 创建和格式化 WSDL

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

? 版权声明:本文为博主原创文章,转载请注明出处 Struts2动态方法调用 - 默认:默认执行方法中的execute方法,若指定类中没有该方法,默认返回success <package name="default" extends="struts-default" namespace="/"> <action name="add" class="org.struts.dynamicmethod.a

Ruby学习之mixin

直接上代码: module Action def jump @distance = rand(4) + 2 puts "I jumped forward #{@distance} feet!" end end class Rabbit include Action attr_reader :name def initialize(name) @name = name end end class Cricket include Action attr_reader :name def i

动态调用服务

利用动态调用服务,实现.net下类似Dubbo的玩法. 分布式微服务现在成为了很多公司架构首先项,据我了解,很多java公司架构都是 Maven+Dubbo+Zookeeper基础上扩展的. Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合).从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务

Ruby学习笔记

Ruby学习笔记 Ruby语言中,以对象为基本单位,可以说所有的元素都是对象.按照之前对于面向对象程序的理解,对象是指包含了特定属性和方法集合的一组程序.对象由类来定义,具体的表现为对象实例.也就是说,对象是类的实例化[2]. Ruby语言的基础元素 对象:数值对象.字符串对象.正则表达式对象.时间对象.文件对象.目录对象.数组.哈希.例外对象等 数值对象   由于Ruby中一切数据都是对象,所以我们处理的数字实际上也是对象. a = 10,这样一个简单的赋值语句,实际上应当理解为 a = Nu

Ruby学习的一天-window下环境搭建及Ruby基础

学习Ruby参考教程: http://www.w3cschool.cc/ruby/ruby-installation-windows.html windowx下的ruby学习一.安装ruby,下载最新window稳定版ruby,这里是1.9.3版本点击next安装直到完成,为了方便,在安装界面下方会有个复选框提示是否需要安装watir,DevKit和环境配置的选项,这里勾选了,就不用那么麻烦配置了.安装完成后直接进入命令行,输入ruby -v .如果不出问题,应该会显示当前ruby版本信息. 二

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

我们继续C#基础知识的学习,这篇文章主要要讲的是我们C#程序员迈向高级C#程序员的关键性的一步. 有的朋友会说事实不是这样的,我不用反射就不能开发吗?当然可以,但是用与不用肯定是不一样的,任何复杂抽象的分层架构或者说是复杂的设计模式均是建立在这些基础之上的,比如我们要进行模块化.组件化开发,要严格的消除模块之间的耦合,要进行动态接口调用.这样的强大而灵活的系统开发,必须要用反射才行:任何技术都有它存在的价值和意义,只要我们把它用在合适的位置就能发挥出惊人的力量:能尽可能的减少我们编写的代码,更能

Java学习笔记——动态代理

所谓动态,也就是说这个东西是可变的,或者说不是一生下来就有的.提到动态就不得不说静态,静态代理,个人觉得是指一个代理在程序中是事先写好的,不能变的,就像上一篇"Java学习笔记--RMI"中的远程代理,其中客户端服务对象就是一个远程服务对象的代理,这个代理可以使得客户在操作时感觉像在操作本地对象一样,远程对象对于客户是透明的.我们可以看出这里的远程代理,是在程序中事先写好的,而本节我们要讨论的远程代理,是由JVM根据反射机制,在程序运行时动态生成的.(以上是本人的理解,如果有不正确的地

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

静态调用,与动态调用. #include <iostream> class Base{ public: virtual int fcn(){ std::cout << "base fcn()" << std::endl; } }; class D1 : public Base{ public: using Base::fcn; int fcn(int){//形参与Base的fcn不一致,所以隐藏了Base的fcn std::cout <<