Let's take another approach to adding Point
objects together. Instead of invoking an instance method of one point and passing another point to that method, let's write a method named sum
that takes any number of Point
objects, adds them together, and returns a new Point
. This method is not an instance method invoked on a Point
object. Rather, it is a class method, invoked through the Point
class itself. We might invoke the sum
method like this:
total = Point.sum(p1, p2, p3) # p1, p2 and p3 are Point objects
Keep in mind that the expression Point
refers to a Class
object that represents our point class. To define a class method
for the Point
class, what we are really doing is defining a
singleton method of the Point
object. To define a singleton
method, use the def
statement as usual, but specify the
object on which the method is to be defined as well as the name of
the method. Our class method sum
is defined like this:
[~/point]$ cat -n point_with_sum.rb 1 require 'point' 2 class Point 3 attr_reader :x, :y # Define accessor methods for our instance variables 4 5 def Point.sum(*points) # Return the sum of an arbitrary number of points 6 x = y = 0 7 points.each {|p| x += p.x; y += p.y } 8 Point.new(x,y) 9 end 10 end 11 12 if __FILE__ == $0 13 z = [[1,1],[2,4],[3,2]].map { |p| Point.new(*p) } 14 p z 15 w = Point.sum(*z) 16 p w 17 r = Point.sum(z[0], z[1]) 18 p r 19 end 20
This definition of the class method names the class explicitly, and mirrors the syntax used to invoke the method. Class methods can also be defined using self instead of the class name. Thus, this method could also be written like this:
def self.sum(*points) # Return the sum of an arbitrary number of points x = y = 0 points.each {|p| x += p.x; y += p.y } Point.new(x,y) end
Using self
instead of Point
makes the code slightly less clear, but it's an application of the DRY (Don't Repeat Yourself) principle. If you use self
instead of the class name, you can change the name of a class without having to edit the definition of its class methods.
There is yet another technique for defining class methods. Though it is less clear than the previously shown technique, it can be handy when defining multiple class methods, and you are likely to see it used in existing code:
# Open up the Point object so we can add methods to it class << Point # Syntax for adding methods to a single object def sum(*points) # This is the class method Point.sum x = y = 0 points.each {|p| x += p.x; y += p.y } Point.new(x,y) end # Other class methods can be defined here end
This technique can also be used inside the class definition, where we can use self
instead of repeating the class name:
class Point # Instance methods go here class << self # Class methods go here end end
También podemos poner self.sum
o bien class << self ... end
[~/point]$ ruby point_with_sum.rb [(1,1), (2,4), (3,2)] (6,7) (3,5)
Casiano Rodriguez León 2015-01-07