Alex Martelli’s            Design Patterns              in Python Apresentada originalmente no Google Developer’s Day 2007...
Alex Martelli and Anna Martelli Ravenscroft             EuroPython, Firenze, June 2011                   photo by Josette ...
O melhor livro sobre Python já escrito      (mesmo sendo de 2006)
Saímos cantando os pneus...• Forças: um sub-sistema  rico e complexo oferece  muita funcionalidade útil;  componentes clie...
Solução: o padrão “Façade”• interpor um objeto/classe                                                  Django: classe do d...
Façade é um padrão de projeto• resumo de um problema comum de projeto +    estrutura de uma solução (+ vantagens e desvant...
Alguns UC de Façade• ...na biblioteca padrão de Python... • dbhash é uma fachada para o bsddb     • acesso muito simplifica...
O que é um padrão de projeto• resumo de um problema comum de projeto +    estrutura de uma solução (+ vantagens e desvanta...
Nenhum livro bomde PP em Python
Preferível
Categorias clássicas de PP• Criacionais: formas e modos de instanciar  objetos• Estruturais: composição mútua de classes  ...
Princípios básicos de PP• “programe para uma interface, não  para uma implementação” (GOF) • isto é feito principalmente a...
Princípios básicos de PP• “prefira composição de objetos do que herança  de classes” (GOF) • em Python, segurar ou embrulha...
Python: segurar ou embrulhar? • “Segurar”: objeto O tem um sub-objeto   S como um atributo (talvez uma   propriedade) – só...
Python: segurar ou embrulhar?• “Embrulhar”: segurar (frequentemente com  um nome privado) e delegar (de modo que se  possa...
Ex.: embrulhar para “restringir”class EmbrulhoRestritor(object):   def __init__(self, embrulhado, bloqueios):         self...
Padrões criacionais• não muito comuns em Python...• ... porque basicamente Factory já vem pronto
“Factory jávem pronto”•   Em linguagens que tem o    operador new, a chamada    new Foo() implica que    Foo é uma classe ...
Padrões criacionais [1]“Queremos que apenas uma instância possa existir”   • use um módulo em vez de uma classe     Resolv...
Singleton (“Highlander”) class Singleton(object):     def __new__(cls, *a, **k):         if not hasattr(cls, _inst):      ...
Monoestado (“Borg”)class Borg(object):    _shared_state = {}    def __new__(cls, *a, **k):        obj = super(Borg, cls   ...
Padrões criacionais [2]• “não queremos ser forçados a instanciar uma  classe concreta específica” •  injeção de dependência...
Padrões Estruturais       Subcategoria “Disfarçe/Adaptação:• Adapter: ajustar uma interface (existem variantes    de class...
Adapter• código-cliente γ exige um protocolo C• cógido-fornecedor σ oferece um protocolo diferente    S (com um superconju...
Exemplo simples de Adapter  • C requer o método foobar(foo, bar)  • S fornece o método barfoo(bar, foo)  • por exemplo, σ ...
Adapter de objeto    • por instância, com delegação por embrulho:class EmbrulhadorFoobar(object):    def __init__(self, em...
Adapter de classe (direto)    • por classe, com derivação e auto-delegação:class Foobarador(Barfooador):    def foobar(sel...
Adapter de classe (mixin)    • flexível, bom uso de herança múltipla:class BF2FB:    def foobar(self, foo, bar):        ret...
Adapter: Usos Conhecidos• socket._fileobject: de sockets para objetos “file-    like” (com muito código para gerenciar o buf...
Observações sobre Adapter• alguns adapters reais podem demandar muito código• classes mixin são uma ótima maneira de auxil...
Facade vs Adapter• Adapter trata de fornecer um determinado    protocolo exigido por código-cliente    • ou, conquistar po...
Padrões comportamentais• Template Method: self-delegation (auto-delegação) • ... “a essência da POO” • algumas de suas var...
Template Method• padrão excelente, nome péssimo • “template” é um termo muito sobrecarregado   • programação genérica em C...
TM Clássico• classe-base abstrata (ABC) oferece “método    organizador” que invoca “métodos gancho”•   na ABC, métodos-gan...
Esqueleto de TMclass AbstractBase(object):    def orgMethod(self):        self.doThis()        self.doThat()class Concrete...
UC: cmd.Cmd.cmdloopdef cmdloop(self):    self.preloop() while True:        s = self.doinput()        s = self.precmd(s)   ...
Justificativa p/ TM Clássico                                             Diferença entre um framework                      ...
Uma escolha de ganchosclass TheBase(object):    def doThis(self):        # provide a default (often a no-op)        pass  ...
UC: Queue.Queueclass Queue:    ...    def put(self, item):        self.not_full.acquire()        try:             while se...
TM em Queue• Não abstrata, frequentemente usada “no estado”,    implementa todos os métodos ganchos•   sub-classes podem c...
Queue customizadaclass LifoQueueA(Queue):    def _put(self, item):        self.queue.appendleft(item)class LifoQueueB(Queu...
Fatorando os ganchos• “método organizador” em uma classe• “métodos gancho” em outra classe• UC: HTML formatter vs writer• ...
TM + introspection• classe “organizadora” pode examinar classe  “gancho” (talvez descendente) em tempo  de execução • desc...
UC: cmd.Cmd.docmddef docmd(self, cmd, a):    ...    try:         fn = getattr(self, do_ + cmd)    except AttributeError:  ...
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Alex Martelli's Python Design Patterns
Próximos SlideShares
Carregando em…5
×

Alex Martelli's Python Design Patterns

2.654 visualizações

Publicada em

Alex Martelli's 45' talk about Design Patterns translated to Brazilian Portuguese under permission from the author.

PT-BR:
A palestra de 45 min sobre Padrões de Projeto do Alex Martelli traduzida para o português do Brasil, com a permissão do autor.

Publicada em: Tecnologia
  • Seja o primeiro a comentar

Alex Martelli's Python Design Patterns

  1. 1. Alex Martelli’s Design Patterns in Python Apresentada originalmente no Google Developer’s Day 2007 Vídeo no YouTube: http://bit.ly/okP7hh Traduzida para a PythonBrasil 7 por Luciano Ramalho comautorização de Alex Martelli gentilmente cedida em 23/08/2011
  2. 2. Alex Martelli and Anna Martelli Ravenscroft EuroPython, Firenze, June 2011 photo by Josette Garcia
  3. 3. O melhor livro sobre Python já escrito (mesmo sendo de 2006)
  4. 4. Saímos cantando os pneus...• Forças: um sub-sistema rico e complexo oferece muita funcionalidade útil; componentes clientes interagem com várias partes dessa funcionali- dade, de um jeito que está “fora de controle”• isto causa muitos problemas para programadores do código cliente e também do sub-sistema (complexidade + rigidez)
  5. 5. Solução: o padrão “Façade”• interpor um objeto/classe Django: classe do domínio versus um monte de classes de modelo, para facilitar a api exposta às views de “fachada”, expondo um sub-conjunto controlado da funcionalidade • clientes acessam somente a fachada • a fachada implementa a funcionalidade simples invocando o sub-sistema complexo• a implementação do sub-sistema ganha flexibilidade, os clientes ganham simplicidade
  6. 6. Façade é um padrão de projeto• resumo de um problema comum de projeto + estrutura de uma solução (+ vantagens e desvantagens, alternativas, ...) e: • um nome (mais fácil de lembrar/discutir)• “descrições de objetos e classes que se comunicam, customizados para resolver um problema geral de projeto em um contexto específico” (GOF)• não é: estrutura de dados, algoritmo, arquitetura específica de domínio, recurso de uma linguagem ou de uma biblioteca Façade é uma exceção• tem que ser estudado no contexto de uma linguagem!• tem que fornecer Usos Conhecidos (UC / KU) PP não são inventados, são descobertos por arqueólogos
  7. 7. Alguns UC de Façade• ...na biblioteca padrão de Python... • dbhash é uma fachada para o bsddb • acesso muito simplificado a uma parte da API • também atende à interface dbm (portanto, é também um exemplo do PP Adapter)• os.path: basename, dirname são fachada para split + acesso a item; isdir (etc.) fachada para os.stat + stat.S_ISDIR (etc.)• Façade é um PP estrutural (veremos outro, Adapter, depois; no exemplo do dbhash eles se fundem)
  8. 8. O que é um padrão de projeto• resumo de um problema comum de projeto + estrutura de uma solução (+ vantagens e desvantagens, alternativas, ...) e: • um nome (mais fácil de lembrar/discutir)• “descrições de objetos e classes que se comunicam customizadas para resolver um problema geral de projeto em um contexto específico” (GOF)• um PP não é: estrutura de dados, algoritmo, arquitetura específica de domínio, recurso de uma linguagem ou de uma biblioteca• tem que ser estudado no contexto de uma linguagem!• tem que fornecer Usos Conhecidos (UC / KU)
  9. 9. Nenhum livro bomde PP em Python
  10. 10. Preferível
  11. 11. Categorias clássicas de PP• Criacionais: formas e modos de instanciar objetos• Estruturais: composição mútua de classes ou objetos (o Façade é um PP estrutural)• Comportamental: como classes e objetos interagem e dividem responsabilidades entre si• Cada um pode ser a nível de classe ou a nível de objeto
  12. 12. Princípios básicos de PP• “programe para uma interface, não para uma implementação” (GOF) • isto é feito principalmente através de “tipagem pato” em Python – raramente com interfaces “formais” • semelhante a “polimorfismo baseado em assinatura” nas templates de C++
  13. 13. Princípios básicos de PP• “prefira composição de objetos do que herança de classes” (GOF) • em Python, segurar ou embrulhar • herdar apenas quando é realmente conveniente • expor todos os métodos da super classe (reusar + normalmente sobrescrever + talvez estender) • mas é um acoplamento muito forte!
  14. 14. Python: segurar ou embrulhar? • “Segurar”: objeto O tem um sub-objeto S como um atributo (talvez uma propriedade) – só isso • usa-se self.S.method ou O.S.method • simples, direto, imediato, porém... acoplamento bem forte, frequentemente no eixo errado
  15. 15. Python: segurar ou embrulhar?• “Embrulhar”: segurar (frequentemente com um nome privado) e delegar (de modo que se possa acessar diretamente O.metodo) • delegação explícita (def metodo(self...): self.S.metodo) • automática (via __getattr__) • acoplamento correto (Lei de Deméter) Evitar expressões do tipo a.b.c. porque isso limita a a expor um b que tem um
  16. 16. Ex.: embrulhar para “restringir”class EmbrulhoRestritor(object): def __init__(self, embrulhado, bloqueios): self._embrulhado = embrulhado self._bloqueios = bloqueios def __getattr__(self, nome): if nome in self._bloqueios: raise AttributeError, nome return getattr(self._embrulhado, nome) ... Herança não tem o poder de restringir!
  17. 17. Padrões criacionais• não muito comuns em Python...• ... porque basicamente Factory já vem pronto
  18. 18. “Factory jávem pronto”• Em linguagens que tem o operador new, a chamada new Foo() implica que Foo é uma classe concreta específica. Isso aumenta o acoplamento.• Python é mais flexível, porque Foo() pode ser a invocação de uma classe ou de uma função factory. O cliente não precisa saber.
  19. 19. Padrões criacionais [1]“Queremos que apenas uma instância possa existir” • use um módulo em vez de uma classe Resolve 90% dos casos • não pode ter subclasses, métodos especiais... • crie somente uma instância (sem restrição) • necessário definir exatamente quando criar • singleton (“Highlander”) • criar sub-classes não é tão tranquilo • monoestado (“Borg”) • Guido não curte
  20. 20. Singleton (“Highlander”) class Singleton(object): def __new__(cls, *a, **k): if not hasattr(cls, _inst): cls._inst = super(Singleton, cls).__new__(cls, *a, **k) return cls._instSubclasses são problemáticas, porém:class Foo(Singleton): pass problemaclass Bar(Foo): pass intrínsecof = Foo(); b = Bar(); # ...???... do Singleton
  21. 21. Monoestado (“Borg”)class Borg(object): _shared_state = {} def __new__(cls, *a, **k): obj = super(Borg, cls ).__new__(cls, *a, **k) obj.__dict__ = cls._shared_state return objSubclasses sem problemas, basta fazer:class Foo(Borg): passclass Bar(Foo): passclass Baz(Foo): sobrecarga de _shared_state = {} dados resolve!
  22. 22. Padrões criacionais [2]• “não queremos ser forçados a instanciar uma classe concreta específica” • injeção de dependência • nada se cria “dentro”, tudo vem “de fora” • e se múltiplas criações são necessárias? • subcategoria “Factory” de PPs • pode criar qq. coisa ou reusar o q. já existe • funções factory (e outros invocáveis) • métodos factory (podem ser sobrescritos) • classes factory abstratas
  23. 23. Padrões Estruturais Subcategoria “Disfarçe/Adaptação:• Adapter: ajustar uma interface (existem variantes de classe e de objetos)• Facade: simplificar a interface de um sub-sistema• ... e muitos outros que não vou abordar, como: • Brige: muitas implementações de uma abstração, muitas implementações de uma funcionalidade, sem codificação repetitiva • Decorator: reusar+ajustar sem herança • Proxy: desacoplar acesso/localização
  24. 24. Adapter• código-cliente γ exige um protocolo C• cógido-fornecedor σ oferece um protocolo diferente S (com um superconjunto da funcionalide de C)• código-adaptador α “se infiltra entre eles”: • para γ, α é um fornecedor (produz o protocolo C) • para σ, α é um cliente (consome o protocolo S) • “dentro”, α implementa C (por meio de chamadas apropriadas a S em σ)
  25. 25. Exemplo simples de Adapter • C requer o método foobar(foo, bar) • S fornece o método barfoo(bar, foo) • por exemplo, σ poderia ser: class Barfooer(object): def barfoo(self, bar, foo): ...
  26. 26. Adapter de objeto • por instância, com delegação por embrulho:class EmbrulhadorFoobar(object): def __init__(self, embrulhado): self.e = embrulhado def foobar(self, foo, bar): return self.e.barfoo(bar, foo)foobarador = EmbrulhadorFoobar(barfooador)
  27. 27. Adapter de classe (direto) • por classe, com derivação e auto-delegação:class Foobarador(Barfooador): def foobar(self, foo, bar): return self.barfoo(bar, foo)foobarador = Foobarador(...qq. coisa...)
  28. 28. Adapter de classe (mixin) • flexível, bom uso de herança múltipla:class BF2FB: def foobar(self, foo, bar): return self.barfoo(bar, foo)class Foobarador(BF2FB, Barfooador): passfoobarador = Foobarador(...qq. coisa...)
  29. 29. Adapter: Usos Conhecidos• socket._fileobject: de sockets para objetos “file- like” (com muito código para gerenciar o buffer)• doctest.DocTestSuite: adapta testes doctest para unittest.TestSuite• dbhash: adapta bsddb para dbm• StringIO: adapta str ou unicode para “file-like”• shelve: adapta “dict limitado” (chaves e valores str, métodos básicos) para um dicionário completo • via pickle para qualquer coisa <-> string • + UserDict.DictMixin
  30. 30. Observações sobre Adapter• alguns adapters reais podem demandar muito código• classes mixin são uma ótima maneira de auxiliar na adaptação de protocolos ricos (implementam métodos avançados a partir de métodos fundamentais)• Adapter é encontrado em todos os níveis de complexidade• Em Python, _não_ se trata sempre de classes e suas instâncias (de modo algum!) -- muitas vezes _invocáveis_ são adaptados (via decorators e outras funções de ordem superior, closures, functools, ...)
  31. 31. Facade vs Adapter• Adapter trata de fornecer um determinado protocolo exigido por código-cliente • ou, conquistar polimorfismo via homogeneidade• Facade trata de simplificar uma interface rica quando apenas um sub-conjunto é necessário• Facade frequentemente mascara um subsistema formado por muitas classes/ objetos, Adapter mascara apenas um objeto ou classe
  32. 32. Padrões comportamentais• Template Method: self-delegation (auto-delegação) • ... “a essência da POO” • algumas de suas variantes específicas em Python
  33. 33. Template Method• padrão excelente, nome péssimo • “template” é um termo muito sobrecarregado • programação genérica em C++ • geração de documento a partir de esqueleto • ...• um nome melhor: self-delegation • auto-delegação • diretamente descritivo!
  34. 34. TM Clássico• classe-base abstrata (ABC) oferece “método organizador” que invoca “métodos gancho”• na ABC, métodos-gancho são abstratos• sub-classes concretas implementam os ganchos• código-cliente invoca o método organizador • em alguma referência à ABC (injetor, ou...) • que obviamente refere-se a uma sub-classe concreta
  35. 35. Esqueleto de TMclass AbstractBase(object): def orgMethod(self): self.doThis() self.doThat()class Concrete(AbstractBase): def doThis(self): ... def doThat(self): ...
  36. 36. UC: cmd.Cmd.cmdloopdef cmdloop(self): self.preloop() while True: s = self.doinput() s = self.precmd(s) finis = self.docmd(s) finis = self.postcmd(finis,s) if finis: break self.postloop() Na implementação em Python, os métodos-gancho são implementados com pass na classe abstrata, porque Python é uma linguagem pragática e não ideológica.
  37. 37. Justificativa p/ TM Clássico Diferença entre um framework e uma bibiblioteca: uma biblioteca é um conjunto de funções que vc chama, a organização fica por sua conta. Um framework tem os métodos • o “método organizador” fornece “lógica de organização e que chamam os seus métodos. estrutural” (sequenciamento etc.) • os “métodos gancho” realizam de fato as “ações elementares” • é frequentemente apropriado para fatorar comportamento comuns e variações • deixa claras as responsabilidades e colaborações entre objetos (classes): classe base invoca ganchos, sub-classes os implementam • aplica o “Hollywood Principle”: “dont call us, well call you” - não ligue para nós, nós te ligamos
  38. 38. Uma escolha de ganchosclass TheBase(object): def doThis(self): # provide a default (often a no-op) pass def doThat(self): # or, force subclass to implement # (might also just be missing...) raise NotImplementedError • Implementações default são mais práticas, quando fazem sentido, mas “obrigatórias” servem como boa documentação
  39. 39. UC: Queue.Queueclass Queue: ... def put(self, item): self.not_full.acquire() try: while self._full(): self.not_full.wait() self._put(item) self.not_empty.notify() finally: self.not_full.release() def _put(self, item): ...
  40. 40. TM em Queue• Não abstrata, frequentemente usada “no estado”, implementa todos os métodos ganchos• sub-classes podem customizar o comportamento • sem se preocupar com travas, timing... • comportamento default é FIFO, simples e útil • with no worry about locking, timing, ... • pode-se sobrescrever métodos gancho (__init__, qsize, _empty, _full, _put, _get) E... • ...dados (maxsize, queue), uma exclusividade Python!
  41. 41. Queue customizadaclass LifoQueueA(Queue): def _put(self, item): self.queue.appendleft(item)class LifoQueueB(Queue): def _init(self, maxsize): self.maxsize = maxsize self.queue = list() def _get(self): return self.queue.pop()
  42. 42. Fatorando os ganchos• “método organizador” em uma classe• “métodos gancho” em outra classe• UC: HTML formatter vs writer• UC: SAX parser vs handler• adiciona um eixo de variabilidade/flexibilidade• aproxima-se do PP Strategy: • Strategy: uma classe abstrata por ponto de decisão, e classes concretas indepententes • TM fatorado: classes abstratas e concretas mais “agrupadas”
  43. 43. TM + introspection• classe “organizadora” pode examinar classe “gancho” (talvez descendente) em tempo de execução • descobrir que métodos existem • despachar apropriadamente (incluindo “catch-all” e/ou outros tratamento de erros)
  44. 44. UC: cmd.Cmd.docmddef docmd(self, cmd, a): ... try: fn = getattr(self, do_ + cmd) except AttributeError: return self.dodefault(cmd, a) return fn(a)

×