La dernière fois (Implémenter un modèle avec des états et des comportements (2)), nous avons implémenté StopWatch
avec trois états de deux manières. .. Cette fois, StopWatch
est implémenté en utilisant * decorator *.
Tout d'abord, décrivez la transition d'état avec * decorator *. Il sera plus facile de comprendre s'il s'agit d'une méthode de transition d'état.
from enum import auto
def transit(state):
def decorator(func):
def inner(self, *args, **kwargs):
self.start_stop, self.reset = self._TRANSIT[state]
func(self, *args, **kwargs)
return inner
return decorator
class StopWatch:
WAIT, PAUSE, MEASURE = auto(), auto(), auto()
def __init__(self):
self._TRANSIT = {StopWatch.WAIT: (self.start, lambda *args: None),
StopWatch.PAUSE: (self.start, self.reset_time),
StopWatch.MEASURE: (self.pause, lambda *args: None)}
self._TRANSIT_REVERSED = {v: k for k, v in self._TRANSIT.items()}
self.start_stop, self.reset = self._TRANSIT[StopWatch.WAIT]
@property
def state(self):
return self._TRANSIT_REVERSED[self.start_stop, self.reset]
@transit(MEASURE)
def start(self):
pass
@transit(PAUSE)
def pause(self):
pass
@transit(WAIT)
def reset_time(self):
pass
De plus, essayez de découper la table de transition d'état avec un décorateur. Le décorateur behavior
représente le comportement dans un certain état.
from enum import auto
from state_machine import behavior, transit
class StopWatch:
WAIT, MEASURE, PAUSE = auto(), auto(), auto()
def __init__(self):
self.state = StopWatch.WAIT
@behavior(WAIT, "start")
@behavior(MEASURE, "pause")
@behavior(PAUSE, "start")
def start_stop(self):
pass
@behavior(PAUSE, "reset_time")
def reset(self):
pass
@transit(MEASURE)
def start(self):
pass
@transit(PAUSE)
def pause(self):
pass
@transit(WAIT)
def reset_time(self):
pass
state_machine.py
from functools import wraps
def transit(state):
def decorator(func):
@wraps(func)
def inner(self, *args, **kwargs):
self.state = state
func(self, *args, **kwargs)
return inner
return decorator
def behavior(state, function):
def decorator(func):
@wraps(func)
def inner(self, *args, **kwargs):
if self.state == state:
getattr(self, function)(*args, **kwargs)
else:
func(self, *args, **kwargs)
return inner
return decorator
Bien que l'on suppose que l'état est conservé dans self.state, le même * décorateur * peut être utilisé dans d'autres modèles, il a donc été découpé en tant que module state_machine
.
Au moment du traitement du décorateur, la fonction n'est toujours pas liée, le comportement est donc donné sous forme de chaîne de caractères. Vous pouvez également utiliser la fonction «name» pour appeler une méthode liée à l'exécution. (Seules les pièces applicables sont illustrées ci-dessous.)
Notez que s'il y a un * décorateur * qui n'utilise pas functools.wrap ()
, il ne fonctionnera pas comme prévu. (* Decorator * ne réécrit pas la fonction __name__
lors de l'utilisation de functools.wrap ()
.)
state_machine.py
def behavior(state, function):
...
if self.state == state:
getattr(self, function.__name__)(*args, **kwargs)
...
...
@behavior(PAUSE, reset_time)
def reset(self):
pass
...
Recommended Posts