Métodos de classe não são métodos estáticos, e como tirar proveito disto
Quando trabalhamos com OOP a divisão do código é bem clara. Classes definem um Objeto que possui atributos e comportamentos, comportamento é representado por métodos. Em Ruby tudo segue esta linha sem exceções (blocos não se encaixam perfeitamente assim).
Mas também é comum por exemplo situações onde talvez um método não precise estar associado a um objeto. Ou seja, não faz muito sentido precisar instanciar um objeto desta classe para poder acessar estes métodos.
Esta capacidade é conhecida de outras linguagens como classes estáticas ou métodos estáticos. Em Ruby não temos isto, temos apenas métodos de classe e métodos de instância. Mas o curioso que mesmo os métodos de classe são métodos de instância mas da classe em si.
Por exemplo:
class Utilities
def self.resize_images(images=[])
...
end
end
Entendendo o que é um método de classe
Acima temos um método resize_images que é criado em Utilities. O self no momento da definição do método é Utilities, por este motivo seria o mesmo que definir o método assim def Utilities.resize_images . Como método foi criado em Utilities, você poderá acessa-lo como Utilities.resize_images sem a necessidade de enviar um .new para Utilities.
Uma pequena curiosidade é que as próprias definições de classe em Ruby são objetos, então Utilities (que é uma constante) também é um objeto, e estes objetos possuem como Metaclasse Class. Então por este motivo o que se assemelha a métodos estáticos de linguagens como Java ou AS3 é nada mais do que um método criado no objeto Utilities que é uma instância de Class armazenada em uma constante chamada Utilities.
Por exemplo, pelo IRB crie uma nova classe assim
class Carro ; ende depois execute Object.constants.sort e você vera que agora Object também possui uma constante chamada Carro.
Agora que entendemos como funcionam os métodos de classe, existem outras formas de criar métodos de classe que é através da abertura da metaclasse, por exemplo:
class Utilities
def self.resize_images(images=[])
...
end
def self.rename_images(images=[])
...
end
end
Seria o mesmo que:
class Utilities
class << self
def resize_images(images=[])
...
end
def rename_images(images=[])
...
end
end
end
Você poderia também abrir a classe Utilities com instance_eval para adicionar métodos de classe nela, ou utilizar um módulo chamando-o com extend. Não vou entrar nestes detalhes para não me prolongar de mais.
Formas de empacotar seus métodos
Também não é incomun casos onde você tenha uma classe apenas com métodos de classe, o que é o caso da Utilities. Criando uma classe assim estariámos modularizando o nosso código, mas o que muita gente diria que é melhor criar um módulo ao invés de uma classe e estender as classes com o módulo Utilities. Também seria uma boa opção.
Mas talvez existem casos onde você não deseja ter que abrir a classe e extende-la apenas para ter acesso ao um método, então uma outra forma de modularizar seu código é através de um método pouco conhecido. Como módulos são classes que não podem ser instanciadas você não poderia fazer algo como abaixo:
module Utilities
def resize_images(images=[])
...
end
def rename_images(images=[])
...
end
end
Utilities.resize_images
Utilities.rename_images
Mas você poderia utilizar um module_function para permitir que estes métodos se tornem métodos acessíveis como métodos de classe. Como abaixo:
module Utilities
module_function
def resize_images(images=[])
...
end
def rename_images(images=[])
...
end
end
E agora você poderá chamar os métodos em qualquer lugar, desta forma:
Utilities.resize_images Utilities.rename_images
Então se você possui uma classe que tem apenas métodos de classe, não possui atributos ou acessors talvez seja interessante pensar nesta solução. Acaba sendo um pouco fora da idéia convencional de OOP, mas se pensarmos a fundo veremos que módulos são nada mais que classes que não podem ser instanciadas e já que não precisamos instanciar Utilities este método se encaixa bem.
Uma outra forma de ter o mesmo resultado seria estendendo o módulo com ele mesmo através de extend self , mas para explicar todas as formas e o que está por trás seria necessário um livro sobre Ruby object model e metaprogramação.
2 Comentários to “Métodos de classe não são métodos estáticos, e como tirar proveito disto”
Filipe Chagas diz:
06/11/2009 em 05:40 PM
Olá,
Daniel, métodos de classe podem acessar atributos de instância? Fiz um teste no irb
class Teste attr_accessor :atributo def self.alterar_atributo @atributo = 10 end end => nil teste = Teste.new => #<teste:0xb7acc954> teste.atributo = 2 => 2 puts teste.atributo 2 => nil Teste.alterar_atributo => 10 puts teste.atributo 2 => nil puts Teste.atributo NoMethodError: undefined method `atributo’ for Teste:Class from (irb):12
Fiquei simplesmente sem entender o que aconteceu…
Ved diz:
07/11/2009 em 02:46 PM
Muito bom mesmo! Um excelente complemento para a aula!
Comentário
CATEGORIAS
HomeDesign
SEO
Empreendimento
Cifras
Ruby e Rails
Flex
Photoshop
Flash
XHTML/CSS
JavaScript
Variados
Database
Firefox
Projetos
3D
Projetos
TextMate
Smalltalk
Mac
Livros
ARQUIVO
03/2010 (2)02/2010 (7)
01/2009 (4)
12/2009 (7)
11/2009 (4)
10/2009 (10)
09/2009 (7)
08/2009 (6)
07/2009 (12)
06/2009 (5)
05/2009 (6)
04/2009 (9)
03/2009 (14)
02/2009 (18)
01/2009 (14)
12/2008 (20)
11/2008 (18)
10/2008 (9)
09/2008 (12)
08/2008 (6)
07/2008 (12)
06/2008 (10)
05/2008 (15)
04/2008 (19)




GAIA, o maior amigo do programador Flash
comentado por criação de sites
Seja produtivo consumindo tomates
comentado por Gabriel Sobrinho
Cifras: novas funcionalidades
comentado por Juarez P. A. Filho
Cifras: novas funcionalidades
comentado por Mário Santos
Ganhador da promoção
comentado por Juarez P. A. Filho