Ruby mix-in
Ruby 是一门面向对象的语言,所有一切都是对象包括基本数据类型变量(如:int,double,string,
hash)等,函数,类型本身也是对象。Ruby在语言设计时没有采用C++等语言的多重继承,而是采用Java单继承的方式。也就是说每个类只能有一个父类,但是根据DRY的知道原则,多重继承在面向对象中是非常必要的。Java采用
接口方式实现多重继承,Ruby则用mix-in方式实现。Java的interface不能定义具体的实现,mix-in方式是可以达到实现服用的效果的。
先看一下mix-in的具体实例
class Person
attr_accessor :name, :age, :gender
def initialize(name)
@name = name
end
end
module UsefulFeatures
def come_in(person)
self.current_person = person
#set_current_person(person)
end
def current_person
#self.current_person
@current_person
end
def set_current_person(person)
puts "set current person"
@current_person = person
end
end
class Room
include UsefulFeatures
def current_person=(person)
#self.current_person = person
puts "set current person (use = )"
@current_person = person
end
end
if __FILE__ == $0
jack = Person.new("jack")
puts "name: #{jack.name}"
bob = Person.new("bob")
room = Room.new()
room.come_in(jack)
puts "room current person #{room.current_person.name}"
end
运行结果:
> ruby test_mixin.rb
name: jack
set current person (use = )
room current person jack
可以看到
例子中使用module定义一个类,在ruby中由module定义的类用
include module name
方式在其它类中使用。由module定义的类没有父类,也不能被实例话,因此就避免了复杂的继承树。
注:module中调用self.current_person = "..."实际上是调用Room的current=(person)方法。
如果将UsefulFeatures中的current_person改为
def current_person
self.current_person
#@current_person
end
运行
脚本会得到如下
错误
mix_in.rb:14: stack level too deep (SystemStackError)
因为在Ruby中所有一切都是对象,在ruby中不能直接访问类中的(实例)变量,所以self.current_person实际上调用的是current_person方法。因此current_person被调用无限次,所以报错。这就是一切皆是对象,当然只是其中一点,还有更多的有待与学习。
将UsefulFeatures中的come_in改为
def come_in(person)
#self.current_person = person
set_current_person(person)
end
再次运行程序得到
name: jack
set current person
room current person jack
直接使用UsefulFeatures中的set_current_person方法。mix-in实现的多重继承即避免的复杂的继承树,又达到了方法实现服用的目的。