Analysis of Ruby relay and message-related knowledge, analysis of ruby
Inheritance allows you to create a class as the refinement and specialization of another class ). For example, in our automatic karaoke system, the concept of "Song" is encapsulated in the Song category. Then, as the market grows, we need to provide karaoke support. A karaoke song is no different from other songs (it just does not have a sound track for the lead singer, so we don't have to worry about it ). However, it also includes a set of lyrics and time information. When our automatic karaoke player is playing a karaoke song, the lyrics should scroll along with the music on the screen before the karaoke player.
One way to solve this problem is to define a new class KaraokeSong, that is, adding the Song lyrics.
class KaraokeSong <Song def initialize(name,artist,duration,lyrics) super(name,artist,duration) @lyrics = lyrics endend
The "<Song" in the class definition line tells Ruby that KaraokeSong is a subclass of Song (subclass). Therefore, this also means that Song is the superclass of KaraokeSong)
song = KaraokeSong.new("My Way","Sinatra",255,"And now,the ...")song.to_s -> *Song:My Way--Sinatra(225)*
No lyrics are displayed when the to_s method is called.
This is related to the Mechanism in which Ruby determines which method to call when we send a message to an object. During the initial parsing (parse) of the program code, when Ruby encounters a method call song. in to_s, it does not know where to find the to_s method, but delays the determination until the program starts running. At that time, Ruby looked at the class to which the song belongs. If this class implements the same method as the message name, run this method. Otherwise, Ruby will view the methods in its parent class, and then the grandfather class, where the entire ancestor chain is traced back. In the end, if it does not find a proper method in the ancestor class, Ruby will produce a special behavior, which usually leads to an error.
Let's solve this problem by implementing KaraokeSong # to_s. You have many ways to complete it. Let's start with the method of the most slot. We copy the to_s method from the Song class and add the lyrics information.
class KaraokeSong #... def to_s "KS: #@name--#@artist(#@duration){#@lyrics}" endendsong = KaraokeSong.new("My Way", "Sinatra", 225,"And now,the...")song.to_s ->"KS: My Way--Sinatra(225){And now,the...}"
The value of the instance variable @ lyrics is correctly displayed. However, in this way, the subclass needs to directly access the instance variables of its ancestor. So why is this a bad way to implement to_s?
The answer is related to a good programming style (sometimes called decoupling ). Directly stamp it into the internal structure of the parent class, and check its instance variables explicitly, so that we are closely bound with the implementation of the parent class.
We solve this problem by letting each class handle its own implementation details. When KaraokeSong # to_s is called, we call the to_s method of the parent class to obtain the details of the song. Then, add the lyrics and return the results. The technique used here is the Ruby keyword super. When you call super without parameters, Ruby sends a message to the parent class of the current object, requiring it to call the method with the same name in the subclass. Ruby passes the parameters we used to call the method to the method of the parent class. Now, we can implement the improved to_s method.
class KaraokeSong <Song #Format ourselves as a string by appending #our lyrics to our parent's to_s value. def to_s super+"{#@lyrics}" endendsong = KaraokeSong.new("My Way", "Sinatra" ,225, "And now,the...")song.to_s ->"Song:My Way--Sinatra(225){And now,the...}"
We clearly tell Ruby that KaraokeSong is a subclass of Song, but we do not specify the parent class of the Song class. If you do not specify the parent class when defining a class, Ruby uses the Object class as its parent class by default. This means that the ancestor of all classes is an Object, and the Object instance method is available to all objects in Ruby.