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łączoneWzorzec 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.
Wyzwanie
ŁatwyZbudujmy 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 interfejsICommandw przestrzeni nazwTextEditorz jedną metodąExecute(). Następnie utwórz dwie konkretne klasy poleceń:InsertCommand— w konstruktorze przyjmuje obiektDocumenti ciąg znakówtext. Po wykonaniu dopisuje tekst do dokumentu i wypisujeInserted: {text}DeleteCommand— w konstruktorze przyjmuje obiektDocumenti wartośćint count. Po wykonaniu usuwa z dokumentu ostatnie znakicounti wypisujeDeleted: {count} characters
Document.cs: Utwórz klasęDocumentw 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 znakicount(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 (
insertlubdelete), 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}"
}
}
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ętrznePrzestrzenie nazw i dyrektywyWprowadzenie do klas i obiektówSłowo kluczowe „this”Metody i parametryPola a właściwościKonstruktoryInicjalizatory obiektówPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawowa składnia dziedziczenia (:)Słowo kluczowe 'base'Słowa kluczowe virtual i overrideKlasy sealedBazowa klasa 'object'Powtórzenie – hierarchia pracowników7Zaawansowane funkcje
Przeciążanie operatorówIndeksery (this[])Nadpisywanie ToString()Metody rozszerzającePodsumowanie – własna lista2Właściwości i składowe statyczne
Właściwości automatyczneWłaściwości tylko do odczytu i zapisuPola i metody statyczneKlasy statyczneSkładowe z ciałem wyrażeniowym5Polimorfizm i interfejsy
Polimorfizm czasu kompilacji a czasu wykonaniaInterfejs a klasa abstrakcyjnaWiele interfejsówJawne implementowanie interfejsówRzutowanie w górę i w dółPowtórka — kalkulator kształtów8Zaawansowane koncepcje OOP
Kompozycja zamiast dziedziczeniaTypy generyczne (klasy i metody)Delegaty i zdarzeniaAtrybuty i refleksjaIDisposable i instrukcja usingPodstawy wstrzykiwania zależności11Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu3Architektura klas
Dane instancji a dane statyczneSłowa kluczowe 'readonly' i 'const'Pola zapasowePowtórzenie — menedżer kont bankowych6Hermetyzacja
Modyfikatory dostępuWłaściwości w hermetyzacjiImplementacja ukrywania danychWzorce niezmiennościPowtórka — dane studentów9Argumenty zmiennej liczby
Słowo kluczowe „params”Parametry opcjonalneArgumenty nazwanePrzeciążanie metodPoćwicz samodzielnie: Kompilator C# online