Module与访问权限

Module与访问权限 #

Module #

模块提供了一个命名空间,并避免名称冲突。在 Ruby 中,类其实就是特殊的模块。默认模块外的代码全部都在 main 命名空间中。

定义模块 #

utils.rb

puts 'load module'
COUNT = 10 # => main 命名空间
module StrUtils
  COUNT = 20 # => StrUtils 命名空间
  def sort_words(words)
    words.sort
  end
  def self.echo
    puts "#{COUNT} #{::COUNT}"
  end
end

其中 self 关键字用于定义模块自身的函数,而没有使用 self 仅仅表示在特定的命名空间内定义了一个函数。

: 与 :: #

: 用于构建 Symbol 对象 :: 表示对命名空间的引用。上节例子中 echo() 函数中的 ::COUNT 就表示引用 main 命名空间的常量。

require #

require 用于引入模块,只会被导入一次,重复导入会被忽略,且引入时不包含后缀名。

require './utils'
require './utils'

StrUtils.echo # => 20
puts StrUtils::COUNT # => 20 10

load #

load 类似 require,但是必须包含后缀名,且会被引入多次,所以如果重复引入包含同个常量的模块时会报已经定义的异常。

load './utils.rb'
StrUtils.echo

include #

include 相当于 Java 中的 import,会将模块中定义的函数直接复制到当前命名空间中,所以调用时可以省略前缀。

include StrUtils
# puts echo()
sentents = ['z', 'b', 'e', 'p']
puts StrUtils.sort_words(sentents)
puts sort_words(sentents)

include 还有一个特点是,当一个模块被包含时该模块的 included 方法会被自动调用。

module StrUtils
  def self.included(clazz)
    puts "StrUtils is included in #{clazz}"
  end
end

以上例子中当 StrUtilsinclude 时,方法会被调用,传入的参数为当前类对象。

extend #

extend 功能类似 include,但是 include 是实例级别的(混入的方法由实例调用),而 extend 默认是类级别的(混入的方法由类调用)。

module C
  def c1
    puts 'c1'
  end
end
class Sample
  extend C
end
Sample.c1

include 一样,extend 也有一个回调方法

def self.extended(base)
  puts "A is extended in #{base}"
end

extend 还有一个特点是其可以作用在实例上动态 extend 任何对象。结合 included 方法可以在某个模块被包含时动态为启动包含的对象添加新的 extend

samp = Sample.new
samp.extend C
samp.c1

混合类型 #

Ruby 中使用模块加 include 可以使类变为混合类型,实现类似多重继承的功能。

module A
  def a1
    puts 'a1'
  end

  def a2
    puts 'a2'
  end
end
module B
  def b1
    puts 'b1'
  end

  def b2
    puts 'b2'
  end
end

class Sample
  include A
  include B

  def s1
    puts 's1'
  end
end

samp = Sample.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1

Class 与 Module #

Ruby 中声明 Class 与 Module 通常使用的是常量,但是也可以像普通变量一样进行声明

dog = Module.new do
  def speak
    puts 'speak'
  end
end
cat = Class.new do
  def jump
    puts 'jump'
  end
end
kitty = cat.new
kitty.extend(dog)
kitty.speak

访问权限 #

Ruby 中访问权限分为 public, privateprotected。默认的访问权限为 publicprotected 只能由子类调用。

class Dog
  def initialize(name, breed)
    @name = name
    @breed = breed
  end

  public
  def bark
    puts 'Woof!'
  end

  def echo
    puts info # => 调用 private 方法
  end

  private
  def info
    "name=#{@name}, breed=#{@breed}"
  end

  protected
  def jump
    puts 'Jump!'
  end
end

class SuperDog < Dog
  def fly
    jump  # => 调用父类的 protected 方法
    puts 'fly'
  end
end

dog = Dog.new('Clark', 'foobar')
dog.bark  # => 调用 public 方法
dog.echo  # => 调用 默认 public 方法

super_dog = SuperDog.new('Super Clark', 'foobar')
super_dog.fly

冻结对象 #

Ruby 可以通过 freeze 来冻结对象。冻结对象后,任何修改都是无效的,会直接报 can't modify frozen 异常。

dog.freeze
# can't modify frozen Dog
# dog.breed = 'bar'
if dog.frozen?
  puts 'frozen object'
else
  puts 'normal object'
end
沪ICP备17055033号-2