Nella mia esperienza, alcuni Pattern sono ancora utili in Python e ancora più facili da configurare rispetto a linguaggi più statici. Alcuni modelli OTOH non sono necessari o addirittura disapprovati, come il modello Singleton. Utilizzare invece una variabile o una funzione a livello di modulo. Oppure usa il modello Borg.
Invece di impostare un modello di creazione è spesso sufficiente passare un callable intorno che crea oggetti. Potrebbe essere una funzione, un oggetto con un __call__
metodo o persino una classe, dal momento che non esiste new()
in Python, solo un'invocazione della classe stessa:
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)
Il modello di stato e strategia condivide una struttura molto simile in linguaggi come C ++ e Java. Meno così in Python. Il modello di strategia rimane più o meno lo stesso, ma il modello di stato diventa per lo più inutile. Pattern di stato in linguaggi statici simula il cambio di classe in fase di esecuzione. In Python, puoi fare proprio questo: cambiare la classe di un oggetto in fase di esecuzione. Fintanto che lo fai in modo controllato e incapsulato, dovresti andare bene:
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
I modelli che si basano sulla spedizione di tipi statici non funzioneranno o funzioneranno in modo diverso. Non è necessario scrivere il codice della piastra della caldaia, ad esempio il modello visitatore: in Java e C ++ è necessario scrivere un metodo di accettazione in ogni classe visitabile, mentre in Python è possibile ereditare tale funzionalità attraverso una classe mixin, come 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)
Molte situazioni che richiedono l'applicazione di un Pattern in un linguaggio statico non lo fanno altrettanto in Python. Molte cose possono essere risolte con altre tecniche, come funzioni di ordine superiore (decoratori, fabbriche di funzioni) o meta-classi.