I'm currently studying some Design Patterns in Python and tried to implement the State Patter example in the diagram:
[edit: The orginal problem was found by @jaykip. I was passing the wrng object in the Open/Close objects instantiation, now I just want to cancel the opening/closing process with the buttons]
It happened to be way more complicated than I expected, I've created a class for each of the four states and the open
and close
methods. To simulate the Open and Close Buttons I uused th pynput
module so I can listen to the keyboard and call the open
and close
buttons, to simulate the open and closed door sensor i just call a sleep
function to wait 3 seconds until the door is closed/open.
It was working ok, until i decided to use Threads so the sleep
function call does not block the main program and I could "press button" while the door is closing/opening. Now the state doesn't change as it was supposed to. heres the code and a running example:
from time import sleep
from pynput import keyboard
from threading import Thread
class Open():
def __init__(self, door):
self.door = door
print('Open')
def open(self):
pass
def close(self):
self.door.state = Closing(self.door)
for _ in range(3):
print('.', end='', flush=True)
sleep(1)
self.door.state = Closed(self.door)
class Opening():
def __init__(self, door):
self.door = door
print('Opening', end='')
def open(self):
pass
def close(self):
self.door.state = Closing(self.door)
for _ in range(3):
print('.', end='', flush=True)
sleep(1)
self.door.state = Closed(self.door)
class Closed():
def __init__(self, door):
self.door = door
print('Closed')
def close(self):
pass
def open(self):
self.door.state = Opening(self.door)
for _ in range(3):
print('.', end='', flush=True)
sleep(1)
self.door.state = Open(self.door)
class Closing():
def __init__(self, door):
self.door = door
print('Closing', end='')
def close(self):
pass
def open(self):
self.door.state = Opening(self.door)
for _ in range(3):
if type(self.door.state) == Opening:
print('.', end='', flush=True)
sleep(1)
self.door.state = Open(self.door)
class ElevatorDoor:
def __init__(self):
self.state = Open(self)
def open(self):
Thread(target=self.state.open).start()
def close(self):
Thread(target=self.state.close).start()
if __name__ == '__main__':
door = ElevatorDoor()
def on_press(key):
global door
if key == keyboard.Key.esc:
return False # stop listener
try:
k = key.char # single-char keys
except Exception:
k = key.name # other keys
if k == 'o':
door.open()
if k == 'c':
door.close()
listener = keyboard.Listener(on_press=on_press)
listener.start()
listener.join()
And that is what happens:
<initial state is Open>
Open
<press 'c' key>
Closing...Closed
<wait it finishes and press 'o' key>
Opening...Open
<press 'c' key and while closing press 'o' key>
Closing..Opening...Closed
Open
Any ideas on how to cancel the previous closing Thread so it wont change the state to Clodes and print the "Closed" in the middle of the opening process?
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…