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

Writable Attributes

Sometimes you need to be able to set an attribute from outside the object. For example, let's assume that the duration that is initially associated with a song is an estimate (perhaps gathered from information on a CD or in the MP3 data). The first time we play the song, we get to find out how long it actually is, and we store this new value back in the Songobject.

In languages such as C++ and Java, you'd do this with setter functions.

class JavaSong {                     // Java code

  private Duration myDuration;

  public void setDuration(Duration newDuration) {

    myDuration = newDuration;

  }

}

s = new Song(....)

s.setDuration(length)

In Ruby, the attributes of an object can be accessed as if they were any other variable. We've seen this above with phrases such as aSong.name. So, it seems natural to be able to assign to these variables when you want to set the value of an attribute. In keeping with the Principle of Least Surprise, that's just what you do in Ruby.

class Song

  def duration=(newDuration)

    @duration = newDuration

  end

end

aSong = Song.new("Bicylops", "Fleck", 260)

aSong.duration

»

260

aSong.duration = 257   # set attribute with updated value

aSong.duration

»

257

The assignment ``aSong.duration = 257'' invokes the methodduration=in theaSongobject, passing it257as an argument. In fact, defining a method name ending in an equals sign makes that name eligible to appear on the left-hand side of an assignment.

Again, Ruby provides a shortcut for creating these simple attribute setting methods.

class Song

  attr_writer :duration

end

aSong = Song.new("Bicylops", "Fleck", 260)

aSong.duration = 257

Virtual Attributes

These attribute accessing methods do not have to be just simple wrappers around an object's instance variables. For example, you might want to access the duration in minutes and fractions of a minute, rather than in seconds as we've been doing.

class Song

  def durationInMinutes

    @duration/60.0   # force floating point

  end

  def durationInMinutes=(value)

    @duration = (value*60).to_i

  end

end

aSong = Song.new("Bicylops", "Fleck", 260)

aSong.durationInMinutes

»

4.333333333

aSong.durationInMinutes = 4.2

aSong.duration

»

252

Here we've used attribute methods to create a virtual instance variable. To the outside world, durationInMinutesseems to be an attribute like any other. Internally, though, there is no corresponding instance variable.

This is more than a curiosity. In his landmark book Object-Oriented Software Construction, Bertrand Meyer calls this theUniform Access Principle. By hiding the difference between instance variables and calculated values, you are shielding the rest of the world from the implementation of your class. You're free to change how things work in the future without impacting the millions of lines of code that use your class. This is a big win.

Class Variables and Class Methods

So far, all the classes we've created have contained instance variables and instance methods: variables that are associated with a particular instance of the class, and methods that work on those variables. Sometimes classes themselves need to have their own states. This is where class variables come in.

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