我知道抽象类不是Ruby中的一个特性,当然背后有一个哲学原因,但我想知道是否有办法解决通常使用其他语言(如C ++和C ++)中的抽象类来解决的问题。 Java的。
例如:
我需要三个课程Triangle
,Square
和Circle
。因为这些都是几何图形,所以我在考虑用抽象方法AbstractFigure
编写一个名为get_area
的抽象类,它将由具体类Triangle
,Square
实现。 ,和Circle
。
我如何按照Ruby哲学做到这一点?
答案 0 :(得分:7)
你是正确的,它并不像红宝石那样在一个明确定义的概念中存在,不像其他语言,如Java,它被大量使用。
但是你也很正确,有很多情况需要它。
以下是我用你的例子 -
的方式class AbstractShape
attr_accessor :edges
def initialize
# ...
end
def get_area
raise NoMethodError("Override this implementation")
end
end
class Square < AbstractShape
def initialize
# square-specific stuff
super
end
def get_area
self.edges * foo * bar
end
end
关键是要在顶层定义所有可用的方法以提高可读性和一致性,但如果使用它们,请确保它们引发错误。
如果有一种绝对确定的方法将在所有形状中以相同的方式使用,那么在AbstractShape
attr_accessor
也将继承,因此您可以针对每个形状在每个实例的基础上提供@edges
。但是你仍然可以在AbstractShape
类中引用引用@edges
的方法,因为它们只会使用正确的本地实例变量。
答案 1 :(得分:3)
使用方法AbstractFigure
定义普通类get_area
,只需引发NotImplementedError
。然后,每个派生类都会使用它自己的实现覆盖get_area
方法。
class AbstractFigure
def get_area
raise NotImplementedError.new( 'appropriate error message' )
end
end
class Square < AbstractFigure
def get_area
# implementation here
end
end
答案 2 :(得分:0)
使用Class::new和Module#const_set:
k = Class.new do
def area(width, height)
width*height
end
end
["A", "B"].each { |sub| Object.const_set(sub, Class.new(superclass=k)) }
#=> ["A", "B"]
class A
def perimeter(width, height)
2*(width+height)
end
end
A.superclass
#=> #<Class:0x007fd26a05d5b8>
B.superclass
#=> #<Class:0x007fd26a05d5b8>
A.instance_method(:area).owner
#=> #<Class:0x007fd26a05d5b8>
A.new.area(3,4)
#=> 12
A.new.perimeter(5,10)
#=> 30
k.new.area(2,5)
#=> 10