一些程序语言(如C++和CLOS)提供了多重继承机制:一个类可以继承自多个超类。例如,一个House可能继承自一个Building类(连同Office和Hospital类一起)和Residence类(连同Apartment类一起)。尽管多重继承可能成为一种语言强有力的特征,但是由于它会增加该语言的复杂性和歧义,因此许多面向对象语言都没有加入它。
Ruby支持单继承。然而,它还提供了mixin-它提供了多继承的许多特征。一个mixin是一种"模块"类型。为此,你必须首先理解在Ruby中模块的含义。
在Ruby中,模块是一种把方法和常数分组的方式。它与类相似,但是一个模块没有实例并且也没有子类。也许解释模块的最好方法是举一个例子。假定你正在开发一个制造业应用程序。该程序需要存取大量的科学公式和常数,那么你可以或者是创建一个通用类来把这些放在其中或者是创建一个模块。模块的优点在于,在存取其中的公式时,根本没有任何实例扰乱所带来的烦恼。
module Formulas ACCELERATION = 9.8 LIGHTSPEED = 299792458 def energy (mass) mass*(LIGHTSPEED**2) end def force (mass) mass*ACCELERATION end end |
现在,这些公式方法和常数可以被任何数目的其它类或其自身所使用:
irb(main):046:0> Formulas.force(10) => 98.0 irb(main):047:0≫ Formulas::ACCELERATION =≫ 9.8 |
注意,为了调用一个模块方法或使用一个模块常数,你必须使用类似于调用一个类方法的标志。为了调用一个模块方法,你需要使用模块类名,后面跟着一个点,再跟着模块方法名。为了引用模块常数,你可以使用模块名,后面跟着两个冒号,再跟着常数名。
除了作为方法和常数的"公共"应用以外,模块还可以帮助定义多重继承。一个mixin是一个简单的"包括"有一个类定义的模块。当一个类包括一个模块时,所有的模块中的方法和常数都成为类的实例方法和常数。例如,假定上面定义的Formula模块作为一个mixin被添加到Rectangle类。为此,你要使用"include"关键字:
class Rectangle include Formulas end |
现在,Rectangle的实例具有了它们可以使用的force和energy方法,并且Rectangle类能够访问常数ACCELERATION和LIGHTSPEED:
irb(main):044:0> class Rectangle irb(main):045:1> include Formulas irb(main):046:1> end => Rectangle irb(main):047:0> Rectangle.new(4,5).force(10) => 98.0 irb(main):048:0> Rectangle::LIGHTSPEED => 299792458 |
这意味着,mixin给Ruby中的类带来了许多多重继承的优点,却避开了多重继承中存在的问题。
十一、 控制流
象所有的程序语言一样,Ruby提供了一组控制流命令,这包括条件语句(if/else结构),case语句和循环语句(do,while和for),还提供了象Ada和Java等语言中的异常处理能力。下面是Ruby中的一些控制流语句的示例:
ifarea > 100 "big" else "small" end case height | when 1 | print "stubby\n" | when 2..10 #高度范围为2~10 | print "short\n" | when 10..20 #高度范围为2~10 | print "tall\n" | end aRect = Rectangle.new(4,6) while aRect.area < 100 and aRect.height < 10 aRect.doubleSize() end for element in [2, 9.8, "some string", Math::PI] #遍历对象集合 print "The type is: " + element.type.to_s + "\n&" end |
控制语句通常非常直接,但是如前面的case语句和for循环语句所显示的,Ruby借鉴了其它一些语言特征和普通的面向对象的特性。
异常处理类似于Java中的"try...catch...finally"语句。在Ruby中,它们更改为"begin...rescue...ensure"语句:
begin #实现一些事情 rescue ##处理错误 ensure #做一些清理工作,如关闭一个打开的文件等 end |
为了在你的代码中引发一个异常,你只需要简单地调用raise方法:
if area < 0 raise else if area > 0 and area < 10 raise "Rectangle too small" else if area > 100 raise TooBigException "Rectangle too big" end |
第一个raise调用创建一个RuntimeError。第二个raise创建一个显示一条消息的RuntimeError。最后一个raise调用一个TooBigException的新实例(由它创建一个粗略定义的错误),并设置它的适当消息。
一个Ruby小程序
为了帮助你更好地掌握Ruby的基础知识,我在本文中提供了一个小程序供你学习之用。为了使这个程序工作,你可以下载并把该文件解压到你的文件系统。之后,它将创建一个examples文件夹,在这个目录下共有9个Ruby代码文件(.rb文件)。本文中的代码就包含在这些文件中。另外,你会找到一个testShapes.rb文件,它是测试Ruby的Rectangle,Square和Circle对象的主文件。只需简单地打开一个命令提示符并运行testShapes.rb文件即可。
你将注意到,在testShapes.rb和另外一些代码中,文件以"require"再加上一个文件名开头(象rectangle.rb)。这是在你的Ruby程序中加入或使用来自于其它文件代码的Ruby标志。
总结
Ruby能否接管Java或C#而成为业界领先的现代软件开发语言?尽管Ruby可能变得十分流行,但我对此仍抱有怀疑态度。作为一名在业界摸爬滚打多年的专业人员,我对其偶然性并不感到惊讶,但我还是比较注重实效的。例如,我发现Smalltalk是一种比Java优越的高级语言,然而优越并不会总会赢。现代语言背后总存在大量的技术和市场方面的支持。库,开发工具包,框架,架构,连接器,适配器,支持平台,服务,知识库,能干的开发团队,等等,都会被配置到位以支持象Java这样的程序语言。并且,无论你喜欢与否,Sun和Microsoft主宰下的市场在未来一段时间内肯定还是开发环境的胜者。
那么,为什么还要探讨Ruby呢?作为一种Perl或Python脚本语言的代替(这正是它的最初目的)或快速原型开发工具,Ruby可能特别有用。一些人也已经看到了Ruby的威力,并且开始把Ruby作为一种伟大的方法进行编程教学。根据我的本地Ruby用户组的成员提供的信息,有一些人正在把它应用于测试生产系统。不仅如此,我将邀请你,就象Bruce Tate和Dave Thomas邀请我一样来探讨一下这种语言的力量和美丽之处。即使Ruby不会得到广泛使用,但是随着人们对它的逐渐认识和试用,它一定会找到适应自己的编程环境。