Decorator for use with objects following the state pattern.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | def statemethod(method):
    def call_statemethod(self, *args, **kwargs):
        # Use self.state.<method> if available, else method itself.
        real_method = getattr(self.state, method.func_name, method)
        return real_method(self, *args, **kwargs)
    call_statemethod.default = method
    return call_statemethod
# Sample usage:
class State(object):
    """Base State class, direct parent to non-instantiated states.
       Useful when you have lots of base objects and don't need to store
       per-state data."""
    @classmethod
    def new(cls):
        """Create a new Base object with this as the initial state."""
        return Base(cls.get_state())
    @classmethod
    def get_state(cls):
        """Get the state, for use with an existing Base object"""
        return cls
class InstantiatedState(State):
    """InstantiatedState creates a new object every time get_state is called.
       This allows for independant per-state data storage by multiple base
       objects."""
    @classmethod
    def get_state(cls):
        """Get a state object, for use with an existing Base object"""
        return cls()
class Base(object):
    def __init__(self, initial_state):
        self.state = initial_state
    def ordinary_method(self):
        print "This method is ordinary."
    @statemethod
    def default_method(self):
        print "This is a default method that has not been overridden."
    @statemethod
    def overridden_method(self):
        print "You shouldn't see this."
        assert False
class SimpleState(State):
    @staticmethod
    def overridden_method(base):
        print "The method on %r has been overridden by SimpleState." % base
class DataState(InstantiatedState):
    message = "Awesome."
    def overridden_method(self, base):
        print "This method on %r has been overridden by DataState.  %s" \
                          % (base,                            self.message)
print "Base A"
print "======"
base_a = SimpleState.new()
print "Calling default_method:"
base_a.default_method()
print "Calling overridden_method:"
base_a.overridden_method()
print "Switching to DataState."
base_a.state = DataState.get_state()
print "Calling overridden_method:"
base_a.overridden_method()
print "Changing message."
base_a.state.message = "Excellent."
print "Calling overridden_method:"
base_a.overridden_method()
print
print "Base B"
print "======"
base_b = DataState.new()
print "Calling default_method:"
base_b.default_method()
print "Calling overridden_method:"
base_b.overridden_method()
 | 
The state pattern solves the problem of having one object that, depending on its current state, can act in several different ways. Conceptually, this might be seen as a parent class with several subclasses that the object switches between.
The decorator makes it easy to place a function under the state's control. The original method acts as a default, but if the current state has a method with the same name, it's used instead.
To call the default method after overriding it, use:
base.<method>.default(...)
This is analogous to a super() call in a subclass:
super(Subclass, self).<method>(...)

 Download
Download Copy to clipboard
Copy to clipboard