Wzorzec Stan
Część sekcji Programowanie obiektowe ścieżki Python w Coddy. Lekcja 53 z 64.
Wzorzec Stan pozwala obiektowi zmieniać zachowanie, gdy zmienia się jego stan wewnętrzny. Obiekt sprawia wrażenie, jakby zmieniał swoją klasę w zależności od bieżącego stanu.
Oto proste klasy stanów dla sygnalizacji świetlnej:
class RedState:
def next_state(self, light):
print("Red -> Green")
light.state = GreenState()
def current_color(self):
return "Red"
class GreenState:
def next_state(self, light):
print("Green -> Yellow")
light.state = YellowState()
def current_color(self):
return "Green"
class YellowState:
def next_state(self, light):
print("Yellow -> Red")
light.state = RedState()
def current_color(self):
return "Yellow"Każdy stan określa, co dzieje się podczas przejścia do następnego stanu.
Utwórz klasę kontekstu, która przechowuje bieżący stan:
class TrafficLight:
def __init__(self):
self.state = RedState() # Zacznij od czerwonego
def change(self):
self.state.next_state(self)
def get_color(self):
return self.state.current_color()Sygnalizacja świetlna deleguje działanie do swojego bieżącego obiektu stanu.
Użyj sygnalizacji świetlnej:
light = TrafficLight()
print(f"Current: {light.get_color()}")
light.change() # Czerwone -> Zielone
print(f"Current: {light.get_color()}")
light.change() # Zielone -> Żółte
print(f"Current: {light.get_color()}")
light.change() # Żółte -> Czerwone
print(f"Current: {light.get_color()}")Utwórz kolejny przykład z prostym odtwarzaczem:
class PlayingState:
def play(self, player):
print("Already playing")
def stop(self, player):
print("Stopping music")
player.state = StoppedState()
class StoppedState:
def play(self, player):
print("Starting music")
player.state = PlayingState()
def stop(self, player):
print("Already stopped")
class MusicPlayer:
def __init__(self):
self.state = StoppedState()
def play(self):
self.state.play(self)
def stop(self):
self.state.stop(self)
player = MusicPlayer()
player.play() # Uruchamianie muzyki
player.play() # Muzyka już gra
player.stop() # Zatrzymywanie muzyki
player.stop() # Muzyka jest już zatrzymanaWynik:
Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stoppedNajważniejsza informacja: Wzorzec Stan hermetyzuje zachowanie specyficzne dla danego stanu w oddzielnych klasach i pozwala obiektowi kontekstu delegować działania do bieżącego stanu. Gdy stan się zmienia, zachowanie zmienia się automatycznie. Eliminuje to złożone instrukcje if/else i ułatwia dodawanie nowych stanów.
Wyzwanie
ŁatwyZaimplementuj wzorzec State w pliku state.py dla lampy z jednym przyciskiem. Każde naciśnięcie przełącza lampę cyklicznie między trzema stanami: wyłączona, niski poziom, wysoki poziom, a następnie z powrotem na wyłączoną. Zamiast łańcucha if sprawdzającego ciąg znaków każdy stan jest osobnym obiektem, który wie, co się dzieje po naciśnięciu przycisku.
LampStateto klasa bazowa z metodamipress(lamp)idescribe().OffState,LowStateiHighStateimplementują te metody:presswywołujelamp.set_state(...)z następnym stanem (z wyłączonej na niski poziom, z niskiego poziomu na wysoki, z wysokiego poziomu na wyłączoną), adescribezwracaLamp is off,Lamp is on lowlubLamp is on high.Lampto kontekst: rozpoczyna działanie w stanieOffState,set_statepodmienia obiekt stanu,press_buttondeleguje obsługę do bieżącego stanu, astatuszwraca bieżący opis.
Plik driver.py jest zablokowany: naciska przycisk i wyświetla status. Zwróć uwagę, że Lamp nigdy nie sprawdza, w jakim jest stanie; decydują o tym obiekty stanów.
Spróbuj swoich sił
from state import Lamp
# Obsługa przypadku testowego (nie zmieniać)
test_case = input()
lamp = Lamp()
if test_case == "initial_test":
print(lamp.status())
elif test_case == "one_press_test":
lamp.press_button()
print(lamp.status())
elif test_case == "cycle_test":
for _ in range(4):
print(lamp.status())
lamp.press_button()
elif test_case == "many_presses_test":
for _ in range(7):
lamp.press_button()
print(lamp.status())
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektyParametr selfMetodyAtrybutyMetoda konstruktora (__init__)Powtórzenie – prosty kalkulator4Dziedziczenie
Podstawy dziedziczeniaFunkcja super()Nadpisywanie metodDziedziczenie wielokrotneKolejność rozwiązywania metodPodsumowanie – hierarchia pracowników7Metody specjalne
Wprowadzenie do metod magicznychPrzeciążanie operatorówMagiczne metody kontenerówPowtórka – własna lista10Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy2Dekoratory
Wprowadzenie do dekoratorówDekorator propertyDekorator metody statycznejDekorator metody klasowej5Polimorfizm
Ponowne omówienie nadpisywania metodTypowanie kaczeKlasy i metody abstrakcyjneProjektowanie interfejsówPodsumowanie — kalkulator kształtów8Zaawansowane koncepcje programowania obiektowego
Kompozycja a dziedziczenieMiksyMetody statyczne i klasoweDekoratory klasMenedżery kontekstu11Wzorce projektowe, część 2
Wzorzec PolecenieWzorzec AdapterWzorzec DekoratorWzorzec Metoda szablonowaWzorzec StanWzorzec Kompozyt3Właściwości klas
Zmienne instancji a zmienne klasoweDekoratory właściwościAtrybuty prywatnePowtórzenie — menedżer kont bankowych6Hermetyzacja
Public, Protected, Private — pamięćModyfikatory dostępuUkrywanie informacjiDekoratory właściwości — zaawansowanePodsumowanie — system ewidencji uczniów12Projekt: System zarządzania biblioteką
Przegląd projektuKlasy Book i UserSystem wypożyczeńFunkcja wyszukiwaniaInterfejs administratoraTestowanie i integracjaPoćwicz samodzielnie: Kompilator Python online