Na minha experiência, alguns padrões ainda são úteis em Python e ainda mais fáceis de configurar do que em linguagens mais estáticas. Alguns padrões OTOH simplesmente não são necessários, ou até desaprovados, como o padrão Singleton. Use uma variável ou função no nível do módulo. Ou use o Padrão Borg.
Em vez de configurar um Padrão de Criação, geralmente é suficiente transmitir uma chamada que cria objetos. Pode ser uma função, um objeto com um __call__
método ou mesmo uma classe, já que não existe new()
no Python, apenas uma invocação da própria classe:
def make_da_thing(maker, other, stuff):
da_thing = maker(other + 1, stuff + 2)
# ... do sth
return da_thing
def maker_func(x, y):
return x * y
class MakerClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
...
a = make_da_thing(maker_func, 5, 8)
b = make_da_thing(MakerClass, 6, 7)
O padrão de estado e estratégia compartilha uma estrutura muito semelhante em linguagens como C ++ e Java. Menos no Python. O Padrão de Estratégia permanece mais ou menos o mesmo, mas o Padrão de Estado se torna praticamente desnecessário. O padrão de estado em idiomas estáticos simula a mudança de classe no tempo de execução. No Python, você pode fazer exatamente isso: alterar a classe de um objeto em tempo de execução. Contanto que você o faça de maneira encapsulada e controlada, você deve ficar bem:
class On(object):
is_on = True
def switch(self):
self.__class__ = Off
class Off(object):
is_on = False
def switch(self):
self.__class__ = On
...
my_switch = On()
assert my_switch.is_on
my_switch.switch()
assert not my_switch.is_on
Os padrões que dependem do Static Type Dispatch não funcionarão ou funcionarão de maneira bastante diferente. Você não precisa escrever tanto código da placa da caldeira, por exemplo, Visitor Pattern: em Java e C ++, é necessário escrever um método de aceitação em todas as classes visitáveis, enquanto que no Python você pode herdar essa funcionalidade por meio de uma classe mixin, como Visitable:
class Visitable(object):
def accept(self, visitor):
visit = getattr(visitor, 'visit' + self.__class__.__name__)
return visit(self)
...
class On(Visitable):
''' exactly like above '''
class Off(Visitable):
''' exactly like above '''
class SwitchStatePrinter(object): # Visitor
def visitOn(self, switch):
print 'the switch is on'
def visitOff(self, switch):
print 'the switch is off'
class SwitchAllOff(object): # Visitor
def visitOn(self, switch):
switch.switch()
def visitOff(self, switch):
pass
...
print_state = SwitchStatePrinter()
turn_em_off = SwitchAllOff()
for each in my_switches:
each.accept(print_state)
each.accept(turn_em_off)
Muitas situações que exigem a aplicação de um padrão em uma linguagem estática não o fazem tanto em Python. Muitas coisas podem ser resolvidas com outras técnicas, como funções de ordem superior (decoradores, fábricas de funções) ou meta-classes.