Metaclasse
Em orientação a objetos, uma metaclasse é uma classe cujas instâncias também são classes e não objetos no sentido tradicional. Assim como classes definem o comportamento de certos objetos, metaclasses definem o comportamento de certas classes e suas instâncias.
Nem toda linguagem orientada a objeto suporta metaclasses. Entre as que suportam, a extensão de modificações que podem ser feitas nas classes varia. Cada linguagem possui seu próprio protocolo de metaobjeto, um conjunto de regras que definem como objetos, classes e metaclasses interagem.
Exemplo em Python
Em Python, a classe nativa type
é uma metaclasse. Considere o exemplo abaixo:
class Carro(object): __slots__ = ['marca', 'modelo', 'ano', 'cor'] def __init__(self, marca, modelo, ano, cor): self.marca = marca self.modelo = modelo self.ano = ano self.cor = cor @property def descricao(self): """ Retorna uma descrição do carro. """ return "%s %s %s %s" % (self.cor, self.ano, self.marca, self.modelo)
Em tempo de execução, Carro
é um objeto type
por herança. O código fonte da classe Carro
mostrado acima não inclui detalhes como o tamanho em bytes dos objetos Carro
, sua configuração na memória, como são alocados, que o método __init__
é invocado automaticamente cada vez que um objeto é criado, e assim por diante. Esses detalhes aparecem não somente quando um novo objeto Carro
é criado, mas também cada vez que um atributo na classe é acessado. Em linguagens de programação sem metaclasses, esses detalhes são definidos pela especificação da linguagem e não podem ser modificados. Em Python, a metaclasse nativa type
controla tais detalhes sobre o comportamento de Carro
. Tais detalhes pode ser modificados usando-se outra metaclasse ao invés de type
.
O exemplo acima contém código redundante relacionado aos quatro atributos marca
, modelo
, ano
e cor
. É possível eliminar parte da redundância usando uma metaclasse. Em Python, uma metaclasse é definida como uma subclasse de type
.
class TipoIniciaAtributo(type): def __call__(self, *args, **kwargs): """ Cria uma nova instância. """ # Primeiro, cria um objeto da forma padrão. obj = type.__call__(self, *args) # Adicionalmente, configura-se atributos do novo objeto. for nome in kwargs: setattr(obj, nome, kwargs[nome]) # Retorna o novo objeto. return obj
Essa metaclasse modifica a criação do objeto. Todos os outros aspectos do comportamento da classe e dos objetos ainda seguem o que foi definido por type
.
Agora a classe Carro
pode ser reescrita para usar essa metaclasse acima, o que é feito atribuindo a nova metaclasse em __metaclass__
:
class Carro(object): __metaclass__ = TipoIniciaAtributo __slots__ = ['marca', 'modelo', 'ano', 'cor'] @property def descricao(self): """ Retorna uma descrição do carro. """ return "%s %s %s %s" % (self.cor, self.ano, self.marca, self.modelo)
Objetos Carro
podem então ser instanciados através de:
carros = [ Carro(marca='Toyota', modelo='Prius', ano=2005, cor='green'), Carro(marca='Ford', modelo='Prefect', ano=1979, cor='blue')]
Suporte em linguagens
As seguintes linguagens de programação suportam metaclasses:
- Common Lisp, via CLOS
- Groovy
- Object Pascal (especialmente Borland Delphi)
- Python
- Perl
- Ruby (seguindo o mesmo esquema de Smalltalk)
- Smalltalk
Ver também
- Classe
- Metamodelo
- Metaprogramação
- Protocolo de metaobjeto
- Reflexão
- Adapter