associação pythonbrasil[11] django zope/plone planet Início Logado como (Entrar)

Diferenças para "ArquiteturaDeComponentes"

Diferenças entre as versões de 2 e 3
Revisão 2e 2007-12-08 08:42:03
Tamanho: 2533
Comentário:
Revisão 3e 2007-12-08 08:53:18
Tamanho: 4340
Comentário:
Deleções são marcadas assim. Adições são marcadas assim.
Linha 31: Linha 31:

É uma convenção chamar as interfaces de IAlgumaCoisa, por isso temos IOperacoesInteiros. Não é um erro de digitação. ;-)
Uma vez que temos uma interface, criamos um componente que a implementa a interface, e podemos instanciá-lo:

{{{
#!python
class Calculadora:

    interface.implements(IOperacoesInteiros)

    def somar(self, a, b):
        return a + b

    def subtrair(self, a, b):
        return a - b

    def multiplicar(self, a, b):
        return a * b

    def dividir(self, a, b):
        return a//b

calc = Calculadora() # sem usar a AC
}}}

Agora podemos efetuar uma divisão com a calculadora diretamente digitando apenas calc.dividir(23,5), mas este não é o estilo de programação de componentes. Para usar a arquitetura de componentes, precisamos registrar o componente:

{{{
#!python
component.provideUtility(Calculator())
}}}

Agora, quem precisar fazer operações com inteiros pode encontrar o componente que presta este serviço:

{{{
#!python
calc = component.getUtility(IOperacoesInteiros)
print "Divisão:", calc.dividir(23, 5)
}}}

Observe que você não precisa conhecer o componente, mas apenas a interface. Isto significa que qualquer um pode implementar o componente para você usar. É claro que quando se trata de algo tão banal quanto somar e dividir isto é inútil, mas você pode por exemplo criar uma interface para componentes que conversam com bancos de dados SQL, e então plugar uma utility para cada modelo de banco de dados diferente. Você pode ter quantos componentes quiser, todos implementando a mesma interface, e se eles forem registrados com nomes diferentes você pode escolher na configuração da sua aplicação qual deles deseja usar. Você tem componentes plugáveis, de um jeito muito fácil.

Uma arquitetura de componentes em Python

Autor: Lennart Regebro - 19/nov/2007

Ao construir grandes frameworks você muitas vezes deseja que tudo seja facilmente plugável e extensível. Os objetos precisam ser capazes de interagir uns com os outros mesmo quando esta interação não está prevista inicialmente. Criar este tipo de flexibilidade não é muito difícil, especialmente em uma linguagem dinâmica como Python, mas se você tem que criar um framework para plug-ins toda vez que precisa de um, você acaba não fazendo isso a menos que seja realmente muito necessário.

Assim, é bom ter uma forma padrão para a interação entre objetos e para que eles possam se inspecionar, e uma forma que você possa usar toda vez que precisar. Resumindo, o você precisa de uma arquitetura de componentes. Felizmente, já existe uma para Python, que foi bem implementada, bem testada e vem sendo usada há anos. Seu nome é Zope Component Architecture.

Ah, sim, já posso ouvir você: "Eca! Zope não... Isso só específico para Zope, não é pythonico, só serve para a Web, é cheio de XML. Argh!". Mas você estaria errado. A única coisa não pythonica e "webby" da Zope Component Architecture é que seus módulos se chamam zope.algo. Mas os módulos têm esse nome porque foram escritos pela Zope Corp. Sim, é verdade que o Zope usa XML em sua linguagem de configuração orientada a aspectos. Veja bem, na orientação a aspectos é desejável ter uma linguagem específica para conectar os componentes, e a do Zope é ZCML. Mas a arquitetura de componentes não exige ZCML de nenhuma maneira. É totalmente baseada em Python (exceto por algumas partes escritas em C para maior performance, mas elas também possuem implementações alternativas em Python).

Vamos ver um exemplo realmente estúpido de como usar a arquitetura de componentes. Vamos criar um componente que seja capaz de fazer aritmética com inteiros. Sim, é bem estúpido, porque sempre existiram jeitos de fazer isso em Python, mas foi a melhor idéia que eu tive. Primeiro, a gente define como a aparência externa do componente de aritmética, sua interface:

   1 from zope import interface, component
   2 
   3 class IOperacoesInteiros(interface.Interface):
   4 
   5     def somar(a, b):
   6         """soma dois inteiros"""
   7 
   8     def subtrair(a, b):
   9         """subtrai dois inteiros"""
  10 
  11     def multiplicar(a, b):
  12         """multiplica dois inteiros"""
  13 
  14     def dividir(a, b):
  15         """divide dois inteiros"""

É uma convenção chamar as interfaces de IAlgumaCoisa, por isso temos IOperacoesInteiros. Não é um erro de digitação. ;-) Uma vez que temos uma interface, criamos um componente que a implementa a interface, e podemos instanciá-lo:

   1 class Calculadora:
   2 
   3     interface.implements(IOperacoesInteiros)
   4 
   5     def somar(self, a, b):
   6         return a + b
   7 
   8     def subtrair(self, a, b):
   9         return a - b
  10 
  11     def multiplicar(self, a, b):
  12         return a * b
  13 
  14     def dividir(self, a, b):
  15         return a//b
  16 
  17 calc = Calculadora() # sem usar a AC

Agora podemos efetuar uma divisão com a calculadora diretamente digitando apenas calc.dividir(23,5), mas este não é o estilo de programação de componentes. Para usar a arquitetura de componentes, precisamos registrar o componente:

   1 component.provideUtility(Calculator())

Agora, quem precisar fazer operações com inteiros pode encontrar o componente que presta este serviço:

   1 calc = component.getUtility(IOperacoesInteiros)
   2 print "Divisão:", calc.dividir(23, 5)

Observe que você não precisa conhecer o componente, mas apenas a interface. Isto significa que qualquer um pode implementar o componente para você usar. É claro que quando se trata de algo tão banal quanto somar e dividir isto é inútil, mas você pode por exemplo criar uma interface para componentes que conversam com bancos de dados SQL, e então plugar uma utility para cada modelo de banco de dados diferente. Você pode ter quantos componentes quiser, todos implementando a mesma interface, e se eles forem registrados com nomes diferentes você pode escolher na configuração da sua aplicação qual deles deseja usar. Você tem componentes plugáveis, de um jeito muito fácil.