Un Método de Clase

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-06-18