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

Diferenças para "ArquiteturaDeComponentes"

Diferenças entre as versões de 5 e 15 (10 versões de distância)
Revisão 5e 2007-12-08 09:13:55
Tamanho: 9199
Comentário:
Revisão 15e 2008-11-17 14:20:03
Tamanho: 8895
Comentário:
Deleções são marcadas assim. Adições são marcadas assim.
Linha 7: Linha 7:
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. 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, 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.
Linha 32: Linha 32:
É uma convenção chamar as interfaces de IAlgumaCoisa, por isso temos IOperacoesInteiros. Não é um erro de digitação. ;-) É uma convenção chamar as interfaces de {{{IAlgumaCoisa}}}, por isso temos {{{IOperacoesInteiros}}}. Não é um erro de digitação. ;-)
Linha 51: Linha 51:
        return a//b         return a // b
Linha 56: Linha 56:
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: 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:
Linha 59: Linha 59:
#!python
Linha 66: Linha 65:
#!python
Linha 71: Linha 69:
Note 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. Note 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.
Linha 73: Linha 71:
Also, the ZCA has provisions for extending other components. Lets say that we also want to be able to do modulo of the integers. We define up how a component that would calculate the modulo should look. We could let it extend the previous IIntegerMaths interface, by just subclassing IIntegerMaths, but that would mean that to get Modulo functionality, we need to sublass every implementation of IIntegerMaths. But since since modulo can be calculated by using division, we can implement it as an adapter. First the new interface for modulo maths:

Além disso, a ZCA
permite que você extenda outros componentes. Digamos que você precisa calcular o resto da divisão inteira, ou módulo. Primeiro definimos a aparência do componente que fará isso. Poderíamos extender a interface IOperacoesInteiros, mas isso significa que para obter a funcionalidade de módulo, teríamos que criar sub-classes de todas as implementações de IOperacoesInteiros. Porém, como o módulo pode ser calculado usando a divisão, podemos implementar isso usando um adaptador, ou ''adapter'' no jargão da ZCA. Primeiro, a nova interface:
Além disso, a ZCA permite que você extenda outros componentes. Digamos que você precisa calcular o resto da divisão inteira, ou módulo. Primeiro definimos a aparência do componente que fará isso. Poderíamos extender a interface IOperacoesInteiros, mas isso significa que para obter a funcionalidade de módulo, teríamos que criar sub-classes de todas as implementações de {{{IOperacoesInteiros}}}. Porém, como o módulo pode ser calculado usando a divisão, podemos implementar isso usando um adaptador, ou ''adapter'' no jargão da ZCA. Primeiro, a nova interface:
Linha 105: Linha 101:
Agora podemos obter um componente que implementa IOperacoesInteiros: Agora podemos obter um componente que implementa {{{IOperacoesInteiros}}}:
Linha 108: Linha 104:
#!python
Linha 112: Linha 107:
e agora podemos adaptá-lo à interface IModulador e usar a funcionalidade extendida: e agora podemos adaptá-lo à interface {{{IModulador}}} e usar a funcionalidade extendida:
Linha 115: Linha 110:
#!python
Linha 120: Linha 114:
Note que isto vai funcionar para qualquer componente IOperacoesInteiros. Basta que ele saiba dividir. Desta forma eu extendi '''todos''' os componentes IOperacoesInteiros ao mesmo tempo. Não precisei extender cada uma das implementações de IOperacoesInteiros, mas usando adaptação eu forneco a qualquer implementação existente a funcionalidade modulo. Note que isto vai funcionar para qualquer componente {{{IOperacoesInteiros}}}. Basta que ele saiba dividir. Desta forma eu extendi '''todos''' os componentes {{{IOperacoesInteiros}}} ao mesmo tempo. Não precisei extender cada uma das implementações de {{{IOperacoesInteiros}}}, pois usando adaptação eu forneço a qualquer implementação existente a funcionalidade {{{modulo}}}.
Linha 122: Linha 116:
Será que é assim tão fácil? Se não acredita, faça easy_install zope.component, copie todo o código abaixo em um arquivo, e execute. Funciona mesmo. Tudo o que você precisa para ter a arquitetura de componentes mais bacana do planeta é fazer from zope import interfaces, component, criar interfaces para seus plugins, e passar a acessá-los através de getUtility. Será que é assim tão fácil? Se não acredita, faça {{{easy_install zope.component}}}, copie todo o código abaixo em um arquivo, e execute. Funciona mesmo. Tudo o que você precisa para ter a arquitetura de componentes mais bacana do planeta é fazer {{{from zope import interfaces, component}}}, criar interfaces para seus plugins, e passar a acessá-los através de {{{getUtility}}}.
Linha 124: Linha 118:
Agora, é clar que há muito mais coisas e funcionalidades e operações interessantes que podem ser feitas com a arquitetura de componentes. Existe um novo projeto de documentação da ZCA que foi iniciado pelo Baiju Muthukadan. O livro "" que ele está escrevendo vai te dar mais detalhes. Agora, é claro que há muito mais coisas e funcionalidades e operações interessantes que podem ser feitas com a arquitetura de componentes. Existe um novo projeto de documentação da ZCA que foi iniciado pelo Baiju Muthukadan. O [[http://www.muthukadan.net/docs/zca.html|livro]] que ele está escrevendo dá mais detalhes.
Linha 126: Linha 120:
''Traduzido por LucianoRamalho'' com autorização do autor, Lennart Regebro. ''Traduzido por LucianoRamalho com autorização do autor, Lennart Regebro. Thanks, Lennart!''
Linha 128: Linha 122:
'''Documento original:''' http://regebro.wordpress.com/2007/11/16/a-python-component-architecture/ ''Documento original:'' http://regebro.wordpress.com/2007/11/16/a-python-component-architecture/

Existe um vídeo com a apresentação deste assunto no GrupySP no "GoogleVideo: http://video.google.com/videoplay?docid=5303962278151147403"
Linha 131: Linha 127:
#!python

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, 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:

component.provideUtility(Calculator())

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

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

Note 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.

Além disso, a ZCA permite que você extenda outros componentes. Digamos que você precisa calcular o resto da divisão inteira, ou módulo. Primeiro definimos a aparência do componente que fará isso. Poderíamos extender a interface IOperacoesInteiros, mas isso significa que para obter a funcionalidade de módulo, teríamos que criar sub-classes de todas as implementações de IOperacoesInteiros. Porém, como o módulo pode ser calculado usando a divisão, podemos implementar isso usando um adaptador, ou adapter no jargão da ZCA. Primeiro, a nova interface:

   1 class IModulador(interface.Interface):
   2 
   3     def modulo(a, b):
   4         "devolve o resto da divisão entre dois inteiros"

Agora, criamos e registramos o adapter:

   1 class AdaptadorDivisorModulador:
   2 
   3     interface.implements(IModulador)
   4     component.adapts(IOperacoesInteiros)
   5 
   6     def __init__(self, context):
   7         self.context = context
   8 
   9     def modulo(self, a , b):
  10         return a - (b*self.context.dividir(a, b))
  11 
  12 component.provideAdapter(AdaptadorDivisorModulador)

Note que desta vez não instanciamos a classe. Os adaptadores são instanciados quando você adapta alguma coisa.

Agora podemos obter um componente que implementa IOperacoesInteiros:

calc = component.getUtility(IOperacoesInteiros)

e agora podemos adaptá-lo à interface IModulador e usar a funcionalidade extendida:

mod_calc = IModulador(calc)
print "Módulo:", mod_calc.modulo(23, 5)

Note que isto vai funcionar para qualquer componente IOperacoesInteiros. Basta que ele saiba dividir. Desta forma eu extendi todos os componentes IOperacoesInteiros ao mesmo tempo. Não precisei extender cada uma das implementações de IOperacoesInteiros, pois usando adaptação eu forneço a qualquer implementação existente a funcionalidade modulo.

Será que é assim tão fácil? Se não acredita, faça easy_install zope.component, copie todo o código abaixo em um arquivo, e execute. Funciona mesmo. Tudo o que você precisa para ter a arquitetura de componentes mais bacana do planeta é fazer from zope import interfaces, component, criar interfaces para seus plugins, e passar a acessá-los através de getUtility.

Agora, é claro que há muito mais coisas e funcionalidades e operações interessantes que podem ser feitas com a arquitetura de componentes. Existe um novo projeto de documentação da ZCA que foi iniciado pelo Baiju Muthukadan. O livro que ele está escrevendo dá mais detalhes.

Traduzido por LucianoRamalho com autorização do autor, Lennart Regebro. Thanks, Lennart!

Documento original: http://regebro.wordpress.com/2007/11/16/a-python-component-architecture/

Existe um vídeo com a apresentação deste assunto no GrupySP no "GoogleVideo: http://video.google.com/videoplay?docid=5303962278151147403"

   1 #!/usr/bin/env python2.4
   2 # coding: utf-8
   3 
   4 from zope import interface, component
   5 
   6 class IOperacoesInteiros(interface.Interface):
   7 
   8     def somar(a, b):
   9         """soma dois inteiros"""
  10 
  11     def subtrair(a, b):
  12         """subtrai dois inteiros"""
  13 
  14     def multiplicar(a, b):
  15         """multiplica dois inteiros"""
  16 
  17     def dividir(a, b):
  18         """divide dois inteiros"""
  19         
  20 class Calculadora:
  21 
  22     interface.implements(IOperacoesInteiros)
  23 
  24     def somar(self, a, b):
  25         return a + b
  26 
  27     def subtrair(self, a, b):
  28         return a - b
  29 
  30     def multiplicar(self, a, b):
  31         return a * b
  32 
  33     def dividir(self, a, b):
  34         return a//b
  35 
  36 calc = Calculadora() # sem usar a AC
  37 
  38 # para usar a AC, registrar o componente
  39 component.provideUtility(Calculadora())
  40 
  41 calc = component.getUtility(IOperacoesInteiros)
  42 print "Divisão:", calc.dividir(23, 5)
  43 
  44 # uso de um adaptador para extender um componente
  45 
  46 class IModulador(interface.Interface):
  47 
  48     def modulo(a, b):
  49         "devolve o resto da divisão entre dois inteiros"
  50 
  51 class AdaptadorDivisorModulador:
  52 
  53     interface.implements(IModulador)
  54     component.adapts(IOperacoesInteiros)
  55 
  56     def __init__(self, context):
  57         self.context = context
  58 
  59     def modulo(self, a , b):
  60         return a - (b*self.context.dividir(a, b))
  61 
  62 component.provideAdapter(AdaptadorDivisorModulador)
  63 
  64 calc = component.getUtility(IOperacoesInteiros)
  65 
  66 mod_calc = IModulador(calc)
  67 print "Módulo:", mod_calc.modulo(23, 5)