Menu
Coddy logo textTech

Wzorzec stanu

Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 60 z 70.

Wzorzec State to wzorzec behawioralny, który pozwala obiektowi zmieniać swoje zachowanie, gdy zmienia się jego stan wewnętrzny. 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 trzech komponentów: interfejsu stanu definiującego zachowanie specyficzne dla danego stanu, konkretnych klas stanów implementujących to zachowanie oraz klasy kontekstu przechowującej odwołanie do bieżącego stanu:

public interface IDocumentState
{
    void Publish(Document doc);
}

public class DraftState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Moving to moderation");
        doc.SetState(new ModerationState());
    }
}

public class ModerationState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Publishing document");
        doc.SetState(new PublishedState());
    }
}

public class PublishedState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Already published");
    }
}

Kontekst przechowuje bieżący stan i deleguje do niego działania. Obiekty stanów mogą wywoływać przejścia, wywołując SetState() na kontekście:

public class Document
{
    private IDocumentState _state = new DraftState();
    
    public void SetState(IDocumentState state) => _state = state;
    
    public void Publish() => _state.Publish(this);
}

var doc = new Document();
doc.Publish();  // Przekazywanie do moderacji
doc.Publish();  // Publikowanie dokumentu
doc.Publish();  // Już opublikowano

Wzorzec State eliminuje rozbudowane instrukcje if-else lub switch, które sprawdzają bieżący stan. Każda klasa stanu obsługuje wyłącznie własne zachowanie, co ułatwia utrzymanie kodu i rozszerzanie go o nowe stany.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system sygnalizacji świetlnej z użyciem wzorca Stan. Sygnalizacja świetlna przechodzi cyklicznie przez różne stany (czerwony, żółty, zielony), a każdy stan określa, co się dzieje po zmianie światła. Zamiast używać złożonych instrukcji warunkowych, zamkniesz każdy stan światła w osobnej klasie.

Rozmieścisz kod w trzech plikach:

  • TrafficLightState.cs: Zdefiniuj interfejs ITrafficLightState w przestrzeni nazw Traffic z metodą Change(TrafficLight light). Następnie utwórz trzy konkretne klasy stanów:
    • RedState — gdy wywołana zostanie metoda Change, wypisuje Red - Stop! Changing to Green... i przełącza światło w stan GreenState
    • GreenState — wypisuje Green - Go! Changing to Yellow... i przełącza światło w stan YellowState
    • YellowState — wypisuje Yellow - Caution! Changing to Red... i przełącza światło w stan RedState
  • TrafficLight.cs: Utwórz klasę TrafficLight w tej samej przestrzeni nazw. To klasa kontekstu, która przechowuje bieżący stan. Domyślnie powinna zaczynać w stanie RedState i mieć:
    • metodę SetState(ITrafficLightState state), której obiekty stanów używają do wywoływania przejść
    • metodę Change(), która deleguje działanie do metody Change bieżącego stanu
  • Program.cs: Połącz wszystko, tworząc obiekt TrafficLight i cyklicznie zmieniając stany na podstawie danych wejściowych.

Otrzymasz jedną daną wejściową:

  • Liczbę zmian świateł sygnalizacji świetlnej (liczbę całkowitą)

Utwórz obiekt TrafficLight (który zaczyna od światła czerwonego) i wywołaj Change() określoną liczbę razy.

Na przykład jeśli dane wejściowe to 3, wynikiem powinno być:

Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...

Jeśli dane wejściowe to 5, cykl świateł zatoczy pełne koło:

Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...

Zwróć uwagę, że klasa TrafficLight nie zawiera logiki określającej, co oznacza każdy kolor ani co następuje po nim — cała ta wiedza znajduje się w poszczególnych klasach stanów. Każdy stan odpowiada za własne zachowanie i wywołanie przejścia do następnego stanu!

Spróbuj swoich sił

using System;
using Traffic;

class Program
{
    public static void Main(String[] args)
    {
        // Odczytaj liczbę zmian sygnalizacji świetlnej
        int n = Convert.ToInt32(Console.ReadLine());

        // TODO: Utwórz instancję TrafficLight (domyślnie zaczyna w stanie RedState)

        // TODO: Wywołaj metodę Change() n razy za pomocą pętli
    }
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C# online