# getterdef foo @fooend# setterdef foo= x
@foo= x
end# simpler way to define getters
attr_reader :y,:z# defines getters# simpler way to define getters and setters
attr_accessor :x# defines getters and setters
classPoint
attr_accessor :x,:ydefinitialize(x,y)@x= x
@y= y enddef distFromOrigin
Math.sqrt(@x*@x+@y*@y)endendclassColorPoint<Point
attr_accessor :colordefinitialize(x,y,c="clear")super(x,y)@color= c
endend
在 Ruby 中,子类化用 < 来表现,ColorPoint 是 Point 的子类,它继续了 Point 里全部的方法和变量,以是 ColorPoint 也有 distFromOrigin 的方法,也有 x, y 坐标。可以看出,通过这种继续关系,ColorPoint 不消将 Point 里关于 x, y 及盘算到顶点的间隔的代码再复制一遍,实现了代码的重用。
覆写和动态调理
覆写 (Overriding) 指的是在子类里和父类一样名字的方法会覆写父类的方法。
动态调理 (Dynamic Patching) 也叫 late binding 大概 virtual methods,指的是从子类去调用父类方法,父类方法里可以动态的调理子类的方法。
classAdef m1
self.m2
enddef m2
puts "m2 in A is called"enddef m3
puts "m3 in A is called"endendclassB<Adef dynamicDispatch
self.m1
enddef m2
puts "m2 in B is called"enddef m3
puts "m3 in B is called"endend
b =B.newb.m3# m3 in B is called
b.dynamicDispatch # m2 in B is called
上例中,子类 B 中的方法 m3 覆写了 A 中的 m3,b.dynamicDispatch 调用了 A 中的 m1, m1 里 self.m2的应该调用 A 还是 B 的 方法 m2 呢?由于发起调用的是 b,以是固然调用的是 A 中 m1 的 self.m2,但是会被动态的调用到 B 中的 m2。
动态调理 VS Closure
对比下吗 ML 和 Ruby 的两个例子:
fun even x = if x=0 then true else odd (x-1)
and odd x = if x=0 then false else even (x-1)
fun even x = (x mod 2)=0
fun even x = false
在 ML 中,有 closure,以是背面界说的两个 even 函数,对第一个函数没有任何影响。
classAdef even x
if x==0thentrueelse odd (x-1)endenddef odd x
if x==0thenfalseelse even (x-1)endendendclassB<A# improves odd in B objectsdef even x ; x %2==0endendclassC<A# breaks odd in C objectsdef even x ;falseendendB.new.odd
C.new.odd
由于动态调理 A 中的 even 不会被调用,而是调用子类 B 和子类 C 的 even。对于步调员来说,可以像 B 一样,写出更好的 even 的代码,也大概像 C 一样写 bug。
publicclassSum{// Overloaded sum(). This sum takes two int parameterspublicintsum(int x,int y){return(x + y);}// Overloaded sum(). This sum takes three int parameterspublicintsum(int x,int y,int z){return(x + y + z);}// Overloaded sum(). This sum takes two double parameterspublicdoublesum(double x,double y){return(x + y);}}
由于多继续的复杂性,尚有单继续代码复用的范围性,有了一个新的概念可以管理这个题目,mixin。Mixin 是一些方法的合集,可以被包罗在 class 里,在这个 class 里可以直接用 mixin 里的方法。
moduleDoublerdef double
self+self# assume included in classes w/ +endendclassString
include DoublerendclassPoint
attr_accessor :x,:y
include Doublerdef+ other
ans =Point.newans.x=self.x + other.x
ans.y =self.y + other.y
ans
end
上例中,Doubler 是一个 Mixin 被用在了 String 和 Point 两个类里,使得两个类都有了 double 这个方法,然后在 class 里可以像 Point 里一样去实现 double 里的 + 方法,来相加两个 Point。再看一个例子:
# you define <=> and you get ==, >, <, >=, <= from the mixin# (overrides Object's ==, adds the others)className
attr_accessor :first,:middle,:last
include Comparabledefinitialize(first,last,middle="")@first= first
@last= last
@middle= middle
enddef<=> other
l =@last<=> other.last # <=> defined on stringsreturn l if l !=0
f =@first<=> other.first
return f if f !=0@middle<=> other.middle
endend
a =Name.new("Tom","Li")
b =Name.new("Jame","Chong")
a < b
fun distToOrigin (p:{x:real,y:real}) = ...
fun makePurple (p:{color:string}) = ...
val c :{x:real,y:real,color:string} = {x=3.0, y=4.0, color="green"}
val _ = distToOrigin(c)
val _ = makePurple(c)
List<Point>inCircle(List<Point> pts, Point center,double r){...}
List<Point> result =newArrayList<Point>();for(Point pt: pts)if(pt.distance(center)<= r)
result.add(pt);return result;
inCircle 参数和返回的范例是 Point 的 List,假如我们有 Point 的子类 ColorPoint,就得把这个代码复制一遍。为了代码复用,也不能把 List 设置成泛型,由于假如 List 不是 Point 的子类会出题目。有没有办法能实现一个只允许子范例的泛型?这叫做 限定多态 (bounded polymorphism)