04/29/2010 继承和消息
继承: 允许创建一个类,作为另一个类的精炼(refinement)和特化(specialization).
歌曲 VS 卡拉OK
区别:一首卡拉OK歌曲和歌曲没有什么两样,只是没有主唱的音轨,包括对应的一套歌词以及时间信息。
定义一个新的类:KaraokeSong
“< Song” 表示KaraokeSong是Song的子类(subclass),Song是KaraokeSong的超类(superclass).既KaraokeSong的父类是Song.
class KaraokeSong < Song
def initialize(name, artist, duration, lyrics) #lyrics是歌词
super(name, artist, duration)
@lyrics = lyrics
end
end
在最终的系统中,歌词保存在一个对象中,其中包括文本以及时间信息。
Ruby的调用机制:
当Ruby遇到方法调用song.to_s时,查看song所属的类,如果该类实现了和消息名称相同的方法,就运行这个方法。否则,Ruby就查看其父类中的方法,然后是祖父类,凡此以往追溯整个祖先链。如果最终在祖先类中没有找到合适的方法,Ruby会导致引发一个错误。
例:向song--即karaokeSong类的一个对象--发送消息to_s.
class Song
def initialize(name, artist, duration)
@name = name
@artist = artist
@duration = duration
end
def to_s
"Song: #@name -- #@artist (#@duration) "
end
end
class KaraokeSong < Song
def initialize(name, artist, duration, lyrics)
super(name, artist, duration)
@lyrics = lyrics
end
def to_s
super + "\n#@lyrics" #调用其父类的to_s方法得到歌曲的细节,然后将歌词信息添加上去。
end
end
song = KaraokeSong.new("LOVE", "Nikey", 250, "Hi,baby,i love you...")
puts song.to_s
输出结果:
Song: LOVE -- Nikey (250)
Hi,baby,i love you...
注:若KaraokeSong类中没有定义to_s类,则程序为:
class Song
def initialize(name, artist, duration)
@name = name
@artist = artist
@duration = duration
end
def to_s
"Song: #@name -- #@artist (#@duration) "
end
end
class KaraokeSong < Song
def initialize(name, artist, duration, lyrics)
super(name, artist, duration)
@lyrics = lyrics
end
end
song = KaraokeSong.new("LOVE", "Nikey", 250, "Hi,baby,i love you...")
puts song.to_s
输出结果:
Song: LOVE -- Nikey (250)
因为在KaraokeSong类中没有找到要调用的方法to_s,解释器就查看KaraokeSong的父类Song类,结果找到了to_s方法,就按照Song类中定义的to_s的方法进行输出。
尽量避免让子类去调用其父类的实例变量来使用这样的编程风格,让每个类处理其自身实现细节的方法。
关键字super: 当调用super而不使用参数时,Ruby向当前对象的父类发送一个消息,要求它调用子类中的同名方法。Ruby将原先调用方法时的参数传递给父类的方法。
如果定义一个类时,没有指定其父类,Ruby默认以Object类作为其父类。所以Object类的实例方法对Ruby的所有对象都可用。
Object类中有超过35个的实例方法,而to_s是其中之一。