why, or when to, use a class method?

T

Thufir

Here's the example:

Jukeboxes charge money for each song played, not by the minute. That
makes short songs more profitable than long ones. We may want to
prevent songs that take too long from being available on the SongList.
We could define a class method in SongList that checked to see if a
particular song exceeded the limit. We'll set this limit using a class
constant, which is simply a constant (remember constants? they start
with an uppercase letter) that is initialized in the class body.

class SongList
MaxTime =3D 5*60 # 5 minutes
def SongList.isTooLong(aSong)
return aSong.duration > MaxTime
end
end
song1 =3D Song.new("Bicylops", "Fleck", 260)
SongList.isTooLong(song1) =BB false
song2 =3D Song.new("The Calling", "Santana", 468)
SongList.isTooLong(song2) =BB true

<http://www.ruby-doc.org/docs/ProgrammingRuby/>

Because the definition is declared with "def
SongList.isTooLong(aSong)", this indicates it to be a class variable
for the SongList class, ok so far. Why a class variable? All
SongList objects will use the same method, but wouldn't they use the
same method even if it were an instance method? Methods are declared
on the class, not the instance.


The class variable makes more sense to me, I can see the need better:

"For example, our jukebox may want to record how many times each
particular song has been played. This count would probably be an
instance variable of the Song object. When a song is played, the value
in the instance is incremented. But say we also want to know how many
songs have been played in total. We could do this by searching for all
the Song objects and adding up their counts, or we could risk
excommunication from the Church of Good Design and use a global
variable. Instead, we'll use a class variable.

class Song
@@plays =3D 0
def initialize(name, artist, duration)
@name =3D name
@artist =3D artist
@duration =3D duration
@plays =3D 0
end
def play
@plays +=3D 1
@@plays +=3D 1
"This song: #@plays plays. Total #@@plays plays."
end
end"

There is one @plays per instance, but only one @@plays which all Song
objects share; this I follow.

Why use a class method in the first example, though?




thanks,

Thufir
 
D

David A. Black

Hi --

Because the definition is declared with "def
SongList.isTooLong(aSong)", this indicates it to be a class variable
for the SongList class, ok so far.

It declares it to be a class *method*. It may or may not use a class
variable (actually the example you gave does not).
Why a class variable? All
SongList objects will use the same method, but wouldn't they use the
same method even if it were an instance method? Methods are declared
on the class, not the instance.

There is one @plays per instance, but only one @@plays which all Song
objects share; this I follow.

Why use a class method in the first example, though?

Typically, a class method is used when you have a method that's
directly related to the objects you're using the class to represent,
but that does something at a more general level than a specific
object.

For example, let's say you have a Car class. You want to create
individual cars:

c = Car.new

and do things with them:

c.fill_with_fuel
c.drive(120)

However, you might also want to do things at a more general level that
still have to do with cars. For example:

class Car
def self.brands
["Ford", "Honda", "Toyota", "Volvo" ...]
end
end

This provides a list of all car brands. I've made it a class method
because while every individual car may be of a particular brand, I
don't expect every car to know about every brand. The Car class,
however, is a good place to put general, high-level information about
cars, like a list of all brands.


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing With Rails, Edison, NJ, November 6-9
* Advancing With Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!
 
7

7stud --

Thufir said:
Why a class variable? All
SongList objects will use the same method, but wouldn't they use the
same method even if it were an instance method? Methods are declared
on the class, not the instance.

Why use a class method in the first example, though?

So that you can check whether a Song is too long without having to
create a SongList object:

#---------
class Song
attr_accessor :duration

def initialize(len)
@duration = len
end
end



class SongList
MaxTime = 5*60

def SongList.isTooLong(aSong)
return aSong.duration > MaxTime
end
end

#------------

s = Song.new(10)
puts SongList.isTooLong(s)

Otherwise, you would have to write:

s = Song.new(10)
sl = SongList.new()
puts sl.isTooLong(s)


Does that make sense for this example? Who knows.
 
T

Thufir

So that you can check whether a Song is too long without having to
create a SongList object:
[...]

What would be a case where there's a SongList object, though? Or, if
there are class methods then generally there won't be objects of that
class?


-Thufir
 
7

7stud --

Thufir said:
So that you can check whether a Song is too long without having to
create a SongList object:
[...]

What would be a case where there's a SongList object, though?


class Song
attr_accessor :duration

def initialize(len)
@duration = len
end
end

class SongList
MaxTime = 5*60
attr_accessor :songs

def initialize(song_arr)
@songs = song_arr
end

def isTooLong(aSong)
return aSong.duration > MaxTime
end
end

my_playlist = SongList.new([Song.new(10), Song.new(4)])
song = my_playlist.songs[0]
puts my_playlist.isTooLong(song)




Or, if
there are class methods then generally there won't be objects of that
class?

If you will never have a need to create objects of the class, then I
think you might just create a Module. On the other hand creating a
class where you can call class methods without objects and create
objects and call instance methods gives you more options. More options
allows more flexibility.
 
P

Phrogz

What would be a case where there's a SongList object, though? Or, if
there are class methods then generally there won't be objects of that
class?

class Rectangle
def self.all
@all ||= []
end

def initialize( width, length )
@width, @length = width, length
self.class.all << self
end

def self.square( length )
new( length, length
end

def self.double( width )
new( width, width * 2 )
end
end

r1 = Rectangle.new( 5, 7 )
r2 = Rectangle.square( 15 )
r3 = Rectangle.double( 6 )
p Rectangle.all

That's a very simple example of two common situations for me: using
class methods to report information about all instances of the class
(which I'm manually tracking here), and using class methods as
alternative constructors that return specialized instances.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top