|
class Home(object): |
|
|
|
def __init__(self): |
|
self._fan_state = "OFF" |
|
self._fan_speed = 0 |
|
|
|
def turn_fan_on(self): |
|
self._fan_state = "ON" |
|
|
|
def turn_fan_off(self): |
|
self._fan_state = "OFF" |
|
|
|
def increase_fan_speed(self, offset=1): |
|
self._fan_speed = self._fan_speed + offset |
|
|
|
def decrease_fan_speed(self, offset=1): |
|
self._fan_speed = self._fan_speed – offset |
|
|
|
def get_fan_state(self): |
|
return self._fan_state |
|
|
|
def get_fan_speed(self): |
|
return self._fan_speed |
|
|
|
|
|
class SmartRemote(object): |
|
|
|
def __init__(self, home_instance): |
|
# Our smart home |
|
self.home = home_instance |
|
# stores a log of all the actions that we have performed |
|
self.command_stack = [] |
|
# Decoupled commands |
|
# Notice how the remote is not aware of how the commands are actually implemented. |
|
# It is just responsible for invoking the right command. |
|
self.fan_on_command_class = FanOnCommand |
|
self.fan_off_command_class = FanOffCommand |
|
self.fan_slow_command_class = FanSlowCommand |
|
self.fan_fast_command_class = None |
|
|
|
""" |
|
Since commands are completely decoupled from the invoker, we can easily update the commands without |
|
changing the invoker. |
|
""" |
|
def set_fan_fast_command(self, fan_fast_command): |
|
self.fan_fast_command_class = fan_fast_command |
|
|
|
""" |
|
Invokes the fan on command and adds the command to the stack |
|
""" |
|
def fan_on(self): |
|
|
|
if not self.fan_on_command_class: |
|
raise NotImplementedError("This operation is not supported") |
|
|
|
fan_on_command = self.fan_on_command_class() |
|
fan_on_command.execute(self.home) |
|
self.command_stack.append(fan_on_command) |
|
|
|
""" |
|
Invokes the fan off command and adds the command to the stack |
|
""" |
|
def fan_off(self): |
|
|
|
if not self.fan_off_command_class: |
|
raise NotImplementedError("This operation is not supported") |
|
|
|
fan_off_command = self.fan_off_command_class() |
|
fan_off_command.execute(self.home) |
|
self.command_stack.append(fan_off_command) |
|
|
|
""" |
|
Invokes the fan slow command and adds the command to the stack |
|
""" |
|
def fan_slow(self): |
|
|
|
if not self.fan_slow_command_class: |
|
raise NotImplementedError("This operation is not supported") |
|
|
|
fan_slow_command = self.fan_slow_command_class() |
|
fan_slow_command.execute(self.home) |
|
self.command_stack.append(fan_slow_command) |
|
|
|
""" |
|
Invokes the fan fast command and adds the command to the stack |
|
""" |
|
def fan_fast(self): |
|
|
|
if not self.fan_fast_command_class: |
|
raise NotImplementedError("This operation is not supported") |
|
|
|
fan_fast_command = self.fan_fast_command_class() |
|
fan_fast_command.execute(self.home) |
|
self.command_stack.append(fan_fast_command) |
|
|
|
""" |
|
Undo the last action that was performed. |
|
A major benefit of command pattern is that logging actions/commands becomes easy. |
|
This can be easily extended to create something like a undo/redo feature. |
|
""" |
|
def undo_last_action(self): |
|
|
|
last_command = self.command_stack.pop() |
|
last_command.undo(home) |
|
|
|
|
|
class BaseCommand(object): |
|
|
|
def execute(self, home_instance): |
|
raise NotImplementedError |
|
|
|
def undo(self, home_instance): |
|
raise NotImplementedError |
|
|
|
|
|
class FanOnCommand(BaseCommand): |
|
|
|
def __init__(self): |
|
self._prev_fan_state = None |
|
|
|
def execute(self, home_instance): |
|
home_instance.turn_fan_on() |
|
print ("Fan state is now {0}".format(home_instance.get_fan_state())) |
|
|
|
def undo(self, home_instance): |
|
home_instance.turn_fan_off() |
|
print("UNDO: Fan state is now {0}".format(home_instance.get_fan_state())) |
|
|
|
|
|
class FanOffCommand(BaseCommand): |
|
|
|
def __init__(self): |
|
self._prev_fan_state = None |
|
|
|
def execute(self, home_instance): |
|
home_instance.turn_fan_off() |
|
print("Fan state is now {0}".format(home.get_fan_state())) |
|
|
|
def undo(self, home_instance): |
|
home_instance.turn_fan_on() |
|
print("UNDO: Fan state is now {0}".format(home_instance.get_fan_state())) |
|
|
|
|
|
class FanFastCommand(BaseCommand): |
|
|
|
def __init__(self): |
|
self._prev_fan_speed = None |
|
|
|
def execute(self, home_instance): |
|
home_instance.increase_fan_speed(offset=1) |
|
print("Fan speed is now {0}".format(home_instance.get_fan_speed())) |
|
|
|
def undo(self, home_instance): |
|
home_instance.decrease_fan_speed(offset=1) |
|
print("UNDO: Fan speed is now {0}".format(home_instance.get_fan_speed())) |
|
|
|
|
|
class FanSlowCommand(BaseCommand): |
|
|
|
def execute(self, home_instance): |
|
home_instance.decrease_fan_speed(offset=1) |
|
print("Fan speed is now {0}".format(home_instance.get_fan_speed())) |
|
|
|
def undo(self, home_instance): |
|
home_instance.increase_fan_speed(offset=1) |
|
print("UNDO: Fan speed is now {0}".format(home_instance.get_fan_speed())) |
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
home = Home() |
|
smart_remote = SmartRemote(home) |
|
|
|
# Since the commands and the invoker are decoupled, we can easily |
|
# change the commands. |
|
smart_remote.fan_fast_command_class = FanFastCommand |
|
|
|
smart_remote.fan_on() |
|
smart_remote.fan_fast() |
|
smart_remote.fan_fast() |
|
smart_remote.fan_slow() |
|
|
|
# Notice how easy it is to undo actions. |
|
# This is also useful in keeping a log of actions that have taken place. |
|
smart_remote.undo_last_action() |
|
smart_remote.undo_last_action() |
|
|
|
# Like a responsible citizen always turn the fan off when leaving the room. |
|
smart_remote.fan_off() |