ruby语言本身并没有提供abstract class和abstract method机制。这是ruby的spirit所决定的。但如果我们真的需要定义一个公共抽象类(或者抽象方法)来让子类来实现,又该如何做呢?
我们可以通过在调用方法时抛出 NotImplementedError来防止方法被调用。如(来自《ruby cookbook》的例子):
class Shape2D
def area
raise NotImplementedError.new("#{self.class.name}#area是抽象方法")
end
end
class Square < Shape2D
def initialize(length)
@length = length
end
def area
@length ** 2
end
end
父类Shape2D的方法area就是我们所需要的“抽象方法”了。你不能直接调用:
s1
=
Shape2D
.
new
s1
.
area
这样调用将抛出错误: Shape2D#area是抽象方法 (NotImplementedError)
Shape2D的子类 Square覆写了此方法。由此我们模拟实现了抽象方法。那么抽象类该如何实现呢?自然而然,我们想到如果把类的initialize方法这样处理,那么这样的类将没办法被new生成,不正是我们所需要的抽象类?说干就干:
class Shape2D
def initialize
raise NotImplementedError
.
new(
"
#{self.class.name}#area是抽象类
"
)
end
def area
raise NotImplementedError
.
new(
"
#{self.class.name}#area是抽象方法
"
)
end
end
当你调用Shape2D.new时,解释器将提示你: Shape2D是抽象类(NotImplementedError)
我们已经实现了抽象方法和抽象类,感觉还是不够好,对每一个需要实现抽象类的类来说,我们都需要去写一句:raise NotImplementedError.new...实在不够爽。ruby鼓励我们去修改类的行为,甚至是标准库,那好,我们修改Class类吧,提供类似attr_reader的声明式服务:
class Class
def
abstract(
*
args)
args
.
each
do
|
method_name
|
define_method(method_name)
do
|*
args
|
if
method_name
==
:
initialize
msg
=
"
#{self.class.name}是抽象类
"
else
msg
=
"
#{self.class.name}##{method_name}是抽象方法
"
end
raise NotImplementedError
.
new(msg)
end
end
end
end
OK,如此一来,我们的Shape2D可以写成:
class Shape2D
abstract
:
initialize
,:
area
#
initialize和area是抽象方法
end
尽管在ruby中,抽象类和抽象方法是否有用存在怀疑,不过知道这样的办法总是不错的主意
我们可以通过在调用方法时抛出 NotImplementedError来防止方法被调用。如(来自《ruby cookbook》的例子):
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
父类Shape2D的方法area就是我们所需要的“抽象方法”了。你不能直接调用:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
这样调用将抛出错误: Shape2D#area是抽象方法 (NotImplementedError)
Shape2D的子类 Square覆写了此方法。由此我们模拟实现了抽象方法。那么抽象类该如何实现呢?自然而然,我们想到如果把类的initialize方法这样处理,那么这样的类将没办法被new生成,不正是我们所需要的抽象类?说干就干:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
当你调用Shape2D.new时,解释器将提示你: Shape2D是抽象类(NotImplementedError)
我们已经实现了抽象方法和抽象类,感觉还是不够好,对每一个需要实现抽象类的类来说,我们都需要去写一句:raise NotImplementedError.new...实在不够爽。ruby鼓励我们去修改类的行为,甚至是标准库,那好,我们修改Class类吧,提供类似attr_reader的声明式服务:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
OK,如此一来,我们的Shape2D可以写成:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
尽管在ruby中,抽象类和抽象方法是否有用存在怀疑,不过知道这样的办法总是不错的主意