Inheritance相信大家已经很熟悉了,就是继承,从一个class里面派生出另外一个subclass,例如:
class KaraokeSong < Song
def initialize(name, artist, duration, lyrics)
super(name, artist, duration)
@lyrics = lyrics
end
end
结果是什么?我们在Song的基础上,建立了新的类别,KaraokeSong,在这个例子里面,它实际上是在Song里面添加了一个新的variable,以求获得一种新的states,我们前面说过,ruby way中,可以添加方法来实现添加属性,但是我们为什么不这么做,而使用了继承来达到这个目的?ruby way给我们的方式是:
class Song
def initialize(name,artist,duration,lyrics)
@name=name
@artist=artist
@duration=duration
@lyrics=lyrics
end
end
这里注意:我们下面谈到的属性,只是意义上的属性,不是ruby里面的属性(attributes)
为什么不建议大家使用第2种方式?显而易见的是,一类事物,它的固有属性是不变的,如果它的属性都变了,也就发生了质变,它就不在是此物了,由此我们相信,一个构造完善的类,属性是一定的,但是就如前面我们说的,在不同的人看来,对这些属性的操作上,有不同的方法,而方法在特定的领域变化将是非常剧烈,我们不可能在构造类的时候了解所有应该建立的方法,因为在某些领域,我们不可能是专家,我们也无法了解这么多,所以构造的类,包含的方法也是有限的,因此,当ruby涉及到一些专业领域,添加method就为我们的工作提供了极大的方便。
依然是这句话:我们认为属性的变化,使得物体发生质变,它已经不是我们开始认为的那类事物了,而第2种方式,改变属性以后,还认为这类物品还是以前的那类物品。比如说,我们在车上装了翅膀,让车飞起来,我们还能硬要说它是车吗?至少应该称之为飞车。所以,在属性变化的时候,我们应该另构着一个类。使用第2种方式不仅是意义上的问题,还会带来副作用,我们也可以这样看,一个类,因为某个愿意,我们为它添加了一种新的适合于某个专业领域的属性,结果是什么?结果是:一个不熟悉某个领域的人,要建立这个类的时候,使用new,这是要提供必要的parameters,由于不了解特定领域,而不能给出或者不能正确给出一个parameter,使得这个object都处于一种rick state,危险状态,在实际编程中,你会理解这种危险状态。因此在这里,我们偏好使用inheritance。但是不是说完全就不能使用方式2来override一个initialize method,以求修改它的instance variable,在某些情况下可以,比如说,设计者本身就没有设计完善这个类,没有包括所有普遍属性,比如粗心的设计或者考虑不够周全,使得car类,没有轮子这个属性,这是我们可以添加,当然这样会带来复杂和麻烦,就好像一个根基都倾斜的比萨斜塔,想要把它修正一样的困难和危险,但是这总比使用一辆没有轮子的车好。
方法的调用:
在ruby里面,方法被调用的时候,先在调用方法的object属于的class里面寻找,如果没有再在superclass里面找,一直向前。这里我们认为method属于某个class,而不是属于某个特定的object,最后如果都没有找到调用的方法,发生error---NoMethodError.
为什么使用super:
1)
class Song
def initialize(a,b,c)
@a=a
@b=b
@c=c
end
def to_s
"#@a,#@b,#@c"
end
end
class OtherSong < Song
def initialize(a,b,c,d)
#super(a,b,c)
@aa=a
@bb=b
@cc=c
@d=d
end
end
song = OtherSong.new("a","b",123,"c")
print song.to_s #使用superclass的to_s方法
结果:
,,
2)
class Song
def initialize(a,b,c)
@a=a
@b=b
@c=c
end
def to_s
"#@a,#@b,#@c"
end
end
class OtherSong < Song
def initialize(a,b,c,d)
super(a,b,c) #使用super
@d=d
end
end
song = OtherSong.new("a","b",123,"c")
print song
结果:
a,b,123
大家应该都看见了结果,不使用super时,如果我们对Song的内部实现不了解,结果就产生了错误,这就使得我们“要开车,必须要知道怎么制造车”,这个比喻不一定十分合理。但是上面的例子已经告诉我们一个事实,我们必须捅破superclass的实现,以求的subclass的正确实现,这无疑增加了复杂度,为了建立一个类,我们要学习它的superclass。所以使用super,这使得superclass的implements被隐藏起来,我们对此不需要关心,同样的理由,我们会用在很多设计的很多方面,给出一个跟直观的约定:“我们尽可能的使用methods,而不是使用variables来实现功能,特别时在类的构造的时候,尽量使用superclasses的methods,而不是它的variables”
super用法:
super表示的是一个method,这个method是与调用它的方法同名的在superclass里面的method,简化此句为:
super表示superclass里面与调用super的方法同名的方法
例如:
class Song
def initialize(a,b,c)
@a=a
@b=b
@c=c
end
def to_s
"#@a,#@b,#@c"
end
end
class OtherSong < Song
def initialize(a,b,c,d)
super(a,b,c) #调用superclass里面的initialize方法
@d=d
end
def to_s
super + "c" #调用superclass里面的to_s方法
end
end
由此,superclass里面是什么,这个super就表示成什么样子。比如上面,initialize在superclass里面有3个参数,那么下面的super也有3个参数,to_s没有参数,super也没有参数,必须一致,不然就发生错误(ArgumentError)。
为了更好的说明这个问题,我再写了一个例子:
class Song
def initialize(a,b,c)
@a=a
@b=b
@c=c
end
def to_s
"#@a,#@b,#@c"
end
end
class OtherSong < Song
def initialize(a,b,c,d)
super(a,b,c)
@d=d
end
def to_s
super(1) + "c" #使用了一个Argument
end
end
song = OtherSong.new("a","b",123,"c")
print song
结果:
in `to_s': wrong number of arguments (1 for 0) (ArgumentError)
from a.rb:19:in `to_s'
from a.rb:24
再论super
super提供了一个可以方便访问superclass的机制,使得我们不必刺穿method的真相(我们也不想这么做),就可以获取superclass赋予我们的操控力。
object is An Object
所有的classes都是inheritance Objecgt class,假如我们写一个class,没有制定继承对象,那么这个class将默认继承Object class,这样有什么好处?好处就是我们马上获得了一些特殊的能力,比如说 to_s,每个object都有 to_s 方法,这个方法来源于Object,从某种意义上来说,强制的继承于Object(不论什么类,它的祖先ancestor,都是Object,所以说是强制继承)这种方式提供了一种约束,拿to_s方法来说,也许每个人都有不同的方法来表示 to_s 这个方法,结果造成了混乱的命名,A喜欢用toString,B喜欢getString,这带来了很多的不方便,使用的不方便,还有一些特殊功能的实现也不方便,这种约定,被称之为习惯,在ruby里面我们获得一种习惯,就是当把对象字符串化的时候,我们用to_s,“习惯是一种力量”,陈安之这么认为过,David也这么认为,所以,rails才会这么简单,易用