Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ruby / Yukihiro Matsumoto_Programming Ruby.doc
Скачиваний:
131
Добавлен:
06.06.2015
Размер:
2.71 Mб
Скачать

Instance Variables in Mixins

People coming to Ruby from C++ often ask us, ``What happens to instance variables in a mixin? In C++, I have to jump through some hoops to control how variables are shared in a multiple-inheritance hierarchy. How does Ruby handle this?''

Well, for starters, it's not really a fair question, we tell them. Remember how instance variables work in Ruby: the first mention of an ``@''-prefixed variable creates the instance variable in the current object,self.

For a mixin, this means that the module that you mix into your client class (the mixee?) may create instance variables in the client object and may use attrand friends to define accessors for these instance variables. For instance:

module Notes

  attr  :concertA

  def tuning(amt)

    @concertA = 440.0 + amt

  end

end

class Trumpet

  include Notes

  def initialize(tune)

    tuning(tune)

    puts "Instance method returns #{concertA}"

    puts "Instance variable is #{@concertA}"

  end

end

# The piano is a little flat, so we'll match it

Trumpet.new(-5.3)

produces:

Instance method returns 434.7

Instance variable is 434.7

Not only do we have access to the methods defined in the mixin, but we get access to the necessary instance variables as well. There's a risk here, of course, that different mixins may use an instance variable with the same name and create a collision:

module MajorScales

  def majorNum

    @numNotes = 7 if @numNotes.nil?

    @numNotes # Return 7

  end

end

module PentatonicScales

  def pentaNum

    @numNotes = 5 if @numNotes.nil?

    @numNotes # Return 5?

  end

end

class ScaleDemo

  include MajorScales

  include PentatonicScales

  def initialize

    puts majorNum # Should be 7

    puts pentaNum # Should be 5

  end

end

ScaleDemo.new

produces:

7

7

The two bits of code that we mix in both use an instance variable named @numNotes. Unfortunately, the result is probably not what the author intended.

For the most part, mixin modules don't try to carry their own instance data around---they use accessors to retrieve data from the client object. But if you need to create a mixin that has to have its own state, ensure that the instance variables have unique names to distinguish them from any other mixins in the system (perhaps by using the module's name as part of the variable name).

Iterators and the Enumerable Module

You've probably noticed that the Ruby collection classes support a large number of operations that do various things with the collection: traverse it, sort it, and so on. You may be thinking, ``Gee, it'd sure be nice if myclass could support all these neat-o features, too!'' (If you actually thought that, it's probably time to stop watching reruns of 1960s television shows.)

Well, your classes cansupport all these neat-o features, thanks to the magic of mixins and moduleEnumerable. All you have to do is write an iterator calledeach, which returns the elements of your collection in turn. Mix inEnumerable, and suddenly your class supports things such asmap,include?, andfind_all?. If the objects in your collection implement meaningful ordering semantics using the<=>method, you'll also getmin,max, andsort.

Соседние файлы в папке Ruby