D'après mon expérience, certains Patterns sont toujours utiles en Python, et encore plus faciles à configurer que dans des langages plus statiques. Certains modèles OTOH ne sont tout simplement pas nécessaires, ou même désapprouvés, comme le modèle Singleton. Utilisez plutôt une variable ou une fonction de niveau module. Ou utilisez le modèle Borg.
Au lieu de configurer un modèle de création, il suffit souvent de passer un appelable qui crée des objets. Cela pourrait être une fonction, un objet avec une __call__
méthode ou même une classe, car il n'y new()
en a pas en Python, juste une invocation de la classe elle-même:
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)
State and Strategy Pattern partagent une structure très similaire dans des langages comme C ++ et Java. Moins en Python. Le modèle de stratégie reste plus ou moins le même, mais le modèle d'état devient généralement inutile. Le modèle d'état dans les langages statiques simule le changement de classe lors de l'exécution. En Python, vous pouvez faire exactement cela: changer la classe d'un objet au moment de l'exécution. Tant que vous le faites de manière contrôlée et encapsulée, tout devrait bien se passer:
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
Les modèles qui reposent sur la répartition de type statique ne fonctionneront pas ou fonctionneront de manière très différente. Vous n'avez pas à écrire autant de code de plaque de chaudière, par exemple Visitor Pattern: en Java et C ++, vous devez écrire une méthode accept dans chaque classe visitable, alors qu'en Python vous pouvez hériter de cette fonctionnalité via une classe mixin, comme 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)
De nombreuses situations qui nécessitent l'application d'un modèle dans un langage statique ne le font pas autant en Python. Beaucoup de choses peuvent être résolues avec d'autres techniques, comme des fonctions d'ordre supérieur (décorateurs, usines de fonctions) ou des méta-classes.