`

Programming Ruby(读书笔记)-5章(继承,模块,mixin)

    博客分类:
  • Ruby
 
阅读更多

继承

Ruby支持继承特性。to_s方法是Object内置方法。定义继承的方法

class Child < Parent
#类似java的this的是#{self}

 使用superclass来获取父类

class Parent
end
class Child < Parent
end
Child.superclass # => Parent
再往上就是Object
再往上就是BaseObject
BasicObject.superclass.inspect # => "nil"

 下面使用GServer类来演示一个通过继承实现TCP监听。

require 'gserver'

class LogServer < GServer

  def initialize
    super(12345)
  end
  
  def serve(client)
    puts "client come in #{client}"
    client.puts get_end_of_log_file
  end
  
private 
  
  def get_end_of_log_file
    File.open("system.log") do |log|
	  log.seek(-500, IO::SEEK_END)
	  log.gets
	  log.read
	end
  end
 end 
  server = LogServer.new
  server.start.join

模块

模块可以是一组方法,类,或常量。它有两个好处:模块提供了命名空间,避免命名冲突,还有就是提供了mixin机制。

命名空间

 Ruby的命名空间是定义在模块上,如下:

tut_modules/trig.rb
module Trig
  PI = 3.141592654
  def Trig.sin(x)
    # ..
  end

  def Trig.cos(x)
    # ..
  end
end
#另外一个模块中可以定义相同的sin方法
tut_modules/moral.rb
module Moral
  VERY_BAD = 0
  BAD           = 1
  def Moral.sin(badness)
    # ...
  end
end
#模块常量与类常量一样,统一使用大写。模块方法与类方法定义方式也是一样。
使用这两个模块的代码示例
require_relative 'trig'
requre_relative 'moral'
y = Trig.sin(Trig::PI/4)
wrongdoing = Moral.sin(Moral::VERY_BAD)

#使用方式:模块名.方法 模块名::常量

 Mixins

mixin是通过模块来实现。

模块中定义的方法是以模块名为前缀+.,但是如果没有这个,就类似于类的实例方法。正是通过这种方式,来实现mixin。例如:

module Debug
  def who_am_i?
    "#{self.class.new} (id: #{self.object_id}): #{self.name}"
  end
end

class Phonograph
  include Debug
  attr_reader :name
  
  def initialize(name)
    @name = name
  end
end
p = Phonograph.new("eeee")
p.who_am_i?
#通过include模块,就可以使用模块的所有实例方法。

 关于include:类中引入模块,是添加了一个到模块的引用,如果所引用的模块在其它文件中,需要通过require 来引用文件名。如果模块的方法有改动,将影响所有引用的类。在运行期也是一样。

通过使用这种方式,可以给类添加任意方法,实现了多重继承。

 

如果引入Compareable模块,则类就被添加了(<, <=, ==, >=, and >)操作符以及between?方法(注意操作表示类可以添加这种操作,如p1 > p2 )。这个模块假设引入它的类实现了<=>方法。然后它在需要的时候会回调。如下:

class Peron
  include Comparable
  attr_reader :name
  
  def initialize(name)
    @name = name
  end

  def to_s
    "#{@name}"
  end

  def <=>(other)
    self.name <=> other.name
  end
end
p1 = Person.new("Matz")
p2 = Person.new("Guido")
p3 = Person.new("Larry")
# Compare a couple of names
if p1 > p2
  puts "#{p1.name}'s name > #{p2.name}'s name"
end

# Sort an array of Person objects
puts "Sorted list:"
puts [ p1, p2, p3].sort
produces:
Matz's name > Guido's name
Sorted list:
Guido
Larry
Matz

 

继承与mixin都可以给类添加方法。而mixin则实现了类似于多重继承。

Iterators and the Enumerable Module(迭代器与迭代模块)

Ruby有一个Enumerable模块,如果引入它,类将有map,include,find_all这些方法。而类要做的就是添加一个迭代方法each,返回自身要迭代的元素。

类似于:
def each
  ['a', 'b'].each do |element|
    element
  end
end
  

 

5.5 Composing Modules(组合模块)

Enumerable是标准的mixin,它添加了许多方法,其中包含inject方法,它的语义是:操作集合中的两个元素,把结果做为操作第三个元素的源,直到所有迭代完成。

[ 1, 2, 3, 4, 5 ].inject(:+) # => 15

( 'a'..'m').inject(:+) # => "abcdefghijklm"

我们也可以定义自己类引入Enumerable,并支持inject方法:

#查找元音,这个示例演示通过添加Enumerabler后,支inject方法
#其中要我们实现each方法。
class VowelFinder
  include Enumerable
  
  def initialize(string)
    @string = string
  end

  def each
    @string.scan(/aeiou/) do |vowel|
      yield vowel
    end
  end
end

vf = VowelFinder.new("the quick brown fox jumped")
vf.inject(:+)  # => "euiooue"

 我们还可以通过给Ruby提供的类添加mixin,来新的方法

#通过将Array与Range两个类include我们自定义的mixin,就可以给它们添加方
#法,这个其实还演示了如何给存在类添加mixin。
module Summable
  def sum
    inject(:+) #注意,这个是假设引入类同时引入了Enumerable,因为这个类有
               #inject方法
  end
class Array
  include Summable
end
[1,2,3,4,5].sum   #=>15
('a'..'m').sum       # => "abcdefghijklm"

 Mixins中的实例变量

不建议mixin中提供实例变量,因为如果它需要有自己的状态,那直接提供类好了。

方法的搜索顺序(同名的覆盖顺序)

查找顺序:class->mixins->superclasses(and their mixins)。如果有多个module mixin,则先搜索最后一个。

 

5.6 继承与Mixin的设计原则

 继承用于is a,Mixin用于has a,use a。这类似于java的组合优先继承。

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics