Menu
Coddy logo textTech

Wzorzec polecenia

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

Wzorzec Command to wzorzec behawioralny, który przekształca żądanie w samodzielny obiekt zawierający wszystkie informacje o tym żądaniu. Ta transformacja pozwala przekazywać żądania jako argumenty metod, umieszczać je w kolejce, rejestrować je lub obsługiwać operacje, które można cofnąć.

Wzorzec oddziela obiekt wywołujący operację od obiektu, który wie, jak ją wykonać. Składa się z czterech kluczowych elementów: interfejsu polecenia, konkretnych poleceń, odbiorcy (obiektu, który wykonuje właściwą pracę) oraz inicjatora (obiektu, który uruchamia polecenia).

public interface ICommand
{
    void Execute();
}

public class Light  // Odbiorca
{
    public void TurnOn() => Console.WriteLine("Light is ON");
    public void TurnOff() => Console.WriteLine("Light is OFF");
}

public class TurnOnCommand : ICommand
{
    private Light _light;
    
    public TurnOnCommand(Light light) => _light = light;
    
    public void Execute() => _light.TurnOn();
}

public class TurnOffCommand : ICommand
{
    private Light _light;
    
    public TurnOffCommand(Light light) => _light = light;
    
    public void Execute() => _light.TurnOff();
}

Wywołujący przechowuje i wykonuje polecenia, nie wiedząc, co robią:

public class RemoteControl  // Wywołujący
{
    private ICommand _command;
    
    public void SetCommand(ICommand command) => _command = command;
    
    public void PressButton() => _command.Execute();
}

// Użycie
var light = new Light();
var remote = new RemoteControl();

remote.SetCommand(new TurnOnCommand(light));
remote.PressButton();  // Światło jest włączone

remote.SetCommand(new TurnOffCommand(light));
remote.PressButton();  // Światło jest wyłączone

Wzorzec Command jest szczególnie przydatny do implementowania funkcji cofania, nagrywania makr lub kolejkowania operacji do późniejszego wykonania. Każde polecenie zawiera wszystko, co jest potrzebne do wykonania działania, dzięki czemu system jest bardziej elastyczny i rozszerzalny.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system poleceń edytora tekstu, używając wzorca Command. Utworzysz system, w którym operacje edycji, takie jak wstawianie i usuwanie tekstu, są hermetyzowane jako obiekty poleceń, dzięki czemu edytor może je wykonywać za pośrednictwem wspólnego interfejsu.

Rozmieścisz swój kod w trzech plikach:

  • Command.cs: Zdefiniuj interfejs ICommand w przestrzeni nazw TextEditor z jedną metodą Execute(). Następnie utwórz dwie konkretne klasy poleceń:
    • InsertCommand — w konstruktorze przyjmuje obiekt Document i ciąg znaków text. Po wykonaniu dopisuje tekst do dokumentu i wypisuje Inserted: {text}
    • DeleteCommand — w konstruktorze przyjmuje obiekt Document i wartość int count. Po wykonaniu usuwa z dokumentu ostatnie znaki count i wypisuje Deleted: {count} characters
  • Document.cs: Utwórz klasę Document w tej samej przestrzeni nazw. To odbiorca — obiekt, który faktycznie wykonuje operacje na tekście. Powinien mieć:
    • Prywatne pole typu string do przechowywania zawartości (zainicjuj je pustym ciągiem)
    • Metodę Append(string text), która dodaje tekst do zawartości
    • Metodę RemoveLast(int count), która usuwa ostatnie znaki count (jeśli count przekracza długość zawartości, usuń całą zawartość)
    • Metodę GetContent(), która zwraca bieżącą zawartość
  • Program.cs: Utwórz klasę Editor, która pełni rolę inicjatora. Powinna mieć metodę SetCommand(ICommand command) oraz metodę ExecuteCommand(), która wykonuje bieżące polecenie. W głównym kodzie zademonstruj wzorzec Command, przetwarzając serię operacji edycji.

Otrzymasz następujące dane wejściowe:

  • Liczba poleceń do wykonania
  • Dla każdego polecenia: typ polecenia (insert lub delete), a następnie tekst do wstawienia albo liczbę znaków do usunięcia

Po wykonaniu wszystkich poleceń wypisz zawartość dokumentu w nowym wierszu w formacie Content: {content}.

Na przykład, jeśli dane wejściowe to:

4
insert
Hello
insert
 World
delete
3
insert
!

Wynik powinien być następujący:

Inserted: Hello
Inserted:  World
Deleted: 3 characters
Inserted: !
Content: Hello Wo!

Zauważ, że Editor (inicjator) nie wie nic o manipulowaniu tekstem — po prostu wykonuje dowolne przekazane mu polecenie. Polecenia hermetyzują zarówno działanie, jak i odbiorcę, dzięki czemu łatwo dodać nowe operacje, takie jak ReplaceCommand, bez zmieniania edytora!

Spróbuj swoich sił

using System;
using TextEditor;

// TODO: Utwórz klasę Editor (wywołującą polecenia)
public class Editor
{
    // TODO: Dodaj prywatne pole do przechowywania bieżącego polecenia
    private ICommand _command;

    // TODO: Zaimplementuj metodę SetCommand
    public void SetCommand(ICommand command)
    {
        // TODO: Zapisz polecenie
    }

    // TODO: Zaimplementuj metodę ExecuteCommand
    public void ExecuteCommand()
    {
        // TODO: Wykonaj bieżące polecenie
    }
}

class Program
{
    public static void Main(string[] args)
    {
        // Odczytaj liczbę poleceń
        int n = Convert.ToInt32(Console.ReadLine());

        // Utwórz dokument (odbiorcę)
        Document document = new Document();

        // Utwórz edytor (wywołującego polecenia)
        Editor editor = new Editor();

        // TODO: Przetwórz każde polecenie
        for (int i = 0; i < n; i++)
        {
            string commandType = Console.ReadLine();

            // TODO: Na podstawie commandType utwórz odpowiednie polecenie
            // - Jeśli "insert": odczytaj tekst i utwórz InsertCommand
            // - Jeśli "delete": odczytaj liczbę i utwórz DeleteCommand
            // Następnie ustaw polecenie w edytorze i je wykonaj
        }

        // TODO: Wyświetl końcową zawartość w formacie "Content: {content}"
    }
}
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