- 论坛徽章:
- 0
|
Ruby中的Mixin
当我们谈到继承,我们通常会分开为接口继承和实现继承。如果是单继承,无论是实现继承还是接口继承,都容易理解和使用。即便如此,在C++的著作中,还是提到当我们在继承一个类的时候,不仅仅要想到继承了实现,还要想到一并继承了接口。
多继承更是复杂,很容易走到菱形继承这样一个怪圈。在C#中,只有接口的多继承,并没有实现的多继承——我们不可以指定两个或两个以后的类作为父类。
Ruby中的Mixin是对多重实现继承的一个实现,即实现部分以模块的方式单独出来,模块有其特有的属性,比如不能实例化,不能继承别的类和被别的类继承等 。松本有一个例子很好:- view sourceprint?
- 01 module WriteStream
- 02 def write(str)
- 03 puts str
- 04 end
- 05
- 06 def conflict
- 07 puts "conflict"
- 08 end
- 09 end
- 10
- 11 module ReadStream
- 12 def read
- 13 puts "read data"
- 14 end
- 15
- 16 def conflict
- 17 puts "conflict-read"
- 18 end
- 19 end
- 20
- 21 class Stream
- 22 def getstream
- 23 puts "get stream"
- 24 end
- 25 end
- 26
- 27 class ReadWriteStream < Stream
- 28 include WriteStream
- 29 include ReadStream
- 30 end
- 31
- 32 rw = ReadWriteStream.new
- 33 rw.getstream
- 34 rw.read
- 35 rw.write("haha")
- 36 rw.conflict
复制代码 这个例子就是网络编程中常常会用到的Stream,ReadStream,WriteStream, ReadWriteStream,在C++中这常常是一个菱形继承,而Ruby巧妙地采用了Mixin,从而避免了菱形继承。
在Ruby下的运行结果为:- view sourceprint?
- 1 get stream
- 2 read data
- 3 haha
- 4 conflict-read
复制代码 即使这样,还是回避不了最根本的问题:方法Resolve,即决定到底使用谁的方法。我们在上例中故意制造了一个冲突的方法conflict,我们从运行结果可以看到方法Resolve中结果是ReadStream的conflict方法。我们可以将程序的28行和29行对调:- view sourceprint?
- 1 include ReadStream
- 2 include WriteStream
复制代码 这时我们再次运行这段脚本,结果如下:- view sourceprint?
- 1 get stream
- 2 read data
- 3 haha
- 4 conflict
-
复制代码 注意最后一行,调用conflict方法结果的差别,我们可以知道Ruby中的Mixin是基于include时的顺序来决定方法调用的顺序。 |
|