Wzorzec stanu
Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 98 z 110.
Wzorzec State pozwala obiektowi zmieniać zachowanie, gdy zmienia się jego stan wewnętrzny, sprawiając wrażenie, jakby obiekt zmienił swoją klasę. Zamiast używać złożonych instrukcji warunkowych do obsługi różnych stanów, enkapsulujesz każdy stan we własnej klasie i delegujesz zachowanie do obiektu reprezentującego bieżący stan.
Wzorzec składa się z kontekstu, który przechowuje odwołanie do bieżącego stanu, oraz klas stanu, które definiują zachowanie dla każdego możliwego stanu. Gdy stan kontekstu się zmienia, jego zachowanie zmienia się automatycznie:
abstract class DocumentState {
void publish(Document doc);
String getStatus();
}
class DraftState implements DocumentState {
@override
void publish(Document doc) {
print('Moving to review...');
doc.setState(ReviewState());
}
@override
String getStatus() => 'Draft';
}
class ReviewState implements DocumentState {
@override
void publish(Document doc) {
print('Document published!');
doc.setState(PublishedState());
}
@override
String getStatus() => 'Under Review';
}
class PublishedState implements DocumentState {
@override
void publish(Document doc) {
print('Already published.');
}
@override
String getStatus() => 'Published';
}
class Document {
DocumentState _state = DraftState();
void setState(DocumentState state) => _state = state;
void publish() => _state.publish(this);
String getStatus() => _state.getStatus();
}
void main() {
var doc = Document();
print(doc.getStatus()); // Wersja robocza
doc.publish(); // Przekazywanie do recenzji...
print(doc.getStatus()); // W trakcie recenzji
doc.publish(); // Dokument opublikowany!
print(doc.getStatus()); // Opublikowany
}Każda klasa stanu obsługuje działanie publish() w inny sposób i może przenieść dokument do następnego stanu. Klasa Document nie potrzebuje instrukcji warunkowych, aby sprawdzać swój bieżący stan — po prostu deleguje działanie do aktualnie aktywnego obiektu stanu. Ten wzorzec idealnie sprawdza się w przypadku obiektów o odrębnych trybach działania, takich jak przetwarzanie zamówień, odtwarzacze multimedialne lub systemy przepływu pracy.
Wyzwanie
ŁatwyZbudujmy system sygnalizacji świetlnej z użyciem wzorca Stan! Utworzysz sygnalizację świetlną, która przechodzi przez różne stany, a każdy stan określa kolor światła i sposób przejścia do następnego stanu.
Podzielisz kod na dwa pliki:
traffic_light.dart: Ten plik zawiera klasy stanów i kontekst sygnalizacji świetlnej. Utwórz klasę abstrakcyjnąTrafficLightStatez dwiema metodami:String getColor(), która zwraca bieżący kolor światła, orazvoid next(TrafficLight light), która przełącza światło na następny stan. Zaimplementuj trzy konkretne klasy stanów:RedState— zwracaREDjako kolor i wyświetlaStop! Light is red., gdy wywołana zostanie metodanext(), a następnie przełącza na stanGreenStateGreenState— zwracaGREENjako kolor i wyświetlaGo! Light is green., gdy wywołana zostanie metodanext(), a następnie przełącza na stanYellowStateYellowState— zwracaYELLOWjako kolor i wyświetlaCaution! Light is yellow., gdy wywołana zostanie metodanext(), a następnie przełącza na stanRedState
TrafficLight(kontekst), która rozpoczyna działanie w stanieRedState. Powinna mieć metodęsetState()do zmiany bieżącego stanu, metodęgetColor(), która deleguje zadanie do bieżącego stanu, oraz metodęchange(), która wywołujenext()dla bieżącego stanu.main.dart: Zaimportuj plik sygnalizacji świetlnej i pokaż wzorzec Stan w działaniu. Utwórz obiektTrafficLighti wyświetl jego początkowy kolor. Następnie wywołajchange()trzy razy, wyświetlając kolor po każdej zmianie. W ten sposób zobaczysz, jak światło przechodzi przez wszystkie stany i wraca do początku.
Zwróć uwagę, że klasa TrafficLight nie potrzebuje żadnych instrukcji warunkowych, aby określić swoje zachowanie — każdy stan zna swój kolor i wie, który stan następuje po nim. Sygnalizacja świetlna po prostu deleguje działanie do aktualnie aktywnego stanu!
Oczekiwany wynik:
RED
Stop! Light is red.
GREEN
Go! Light is green.
YELLOW
Caution! Light is yellow.
REDSpróbuj swoich sił
import 'traffic_light.dart';
void main() {
// TODO: Utwórz instancję TrafficLight
// TODO: Wypisz początkowy kolor
// TODO: Wywołaj change() i wypisz kolor (3 razy, aby przejść przez wszystkie stany)
// Pierwsza zmiana: RED -> GREEN
// Druga zmiana: GREEN -> YELLOW
// Trzecia zmiana: YELLOW -> RED
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP
Pliki zewnętrzneBiblioteki i importyWprowadzenie do OOPKlasy a obiektySłowo kluczowe thisMetodyZmienne instancjiPodstawy konstruktorówPowtórka – prosty kalkulator4Bezpieczeństwo wartości null
Wprowadzenie do bezpieczeństwa wartości nullTypy dopuszczające null i niedopuszczające nullOperatory ? i !Słowo kluczowe late a bezpieczeństwo wartości nullOperatory uwzględniające nullBezpieczeństwo wartości null w klasachPodsumowanie — system profili użytkowników7Klasy abstrakcyjne i interfejsy
Klasy abstrakcyjneMetody abstrakcyjneInterfejsy w DartInterfejsy niejawneImplementowanie a rozszerzanieWiele interfejsówPowtórka — kalkulator kształtów10Kolekcje i typy generyczne
Przegląd List, Set i MapKolekcje bezpieczne typowoKlasy generyczneMetody generyczneOgraniczenia typów generycznychIterable i IteratorPowtórka — generyczne przechowywanie danych13Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieMetody rozszerzająceKlasy wywoływalneKlasy zapieczętowane (Dart 3)Rekordy (Dart 3)Wzorce i dopasowywanie (3.0)Typy wyliczeniowe z metodami16Projekt: Zarządzanie biblioteką
Omówienie projektuKlasy książek i użytkowników2Konstruktory w Dart
Konstruktor domyślnyKonstruktory nazwaneListy inicjalizująceKonstruktory stałeKonstruktory fabryczneKonstruktory przekierowującePodsumowanie — budowanie kształtów5Hermetyzacja
Elementy publiczne a prywatneKonwencja prefiksu _Prywatność na poziomie bibliotekiGettery i settery — szczegółowoUkrywanie informacjiPodsumowanie — dane uczniów8Domieszki
Wprowadzenie do domieszekTworzenie domieszekKorzystanie z wielu domieszekSłowo kluczowe on w domieszkachDomieszka a dziedziczenieDomieszka a interfejsPodsumowanie – system zwierząt11Metody specjalne
Nadpisanie toString()Nadpisanie hashCode i ==Interfejs ComparableMetoda call()Nadpisanie noSuchMethodPodsumowanie — własna kolekcja14Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy3Właściwości klas
Elementy instancji a elementy statycznePola final i constZmienne inicjalizowane z opóźnieniemMetody i pola statyczneGettery i setteryPowtórzenie – menedżer kont bankowych6Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superPrzesłanianie metodAdnotacja @overrideSłowo kluczowe final dla klasKonstruktory i dziedziczeniePowtórzenie – hierarchia pracowników9Polimorfizm
Podstawy polimorfizmuPolimorfizm za pomocą interfejsówSprawdzanie typu w czasie działaniaOperatory is i asSłowo kluczowe covariantPodsumowanie — procesor płatności12Asynchroniczne OOP
Futures i async/awaitPodstawy strumieniKontrolery strumieniKonstruktory asynchroniczneAsynchroniczność w metodach klasyPodsumowanie — pobieranie danych15Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytuWzorzec repozytoriumPoćwicz samodzielnie: Kompilator Dart online