Menu
Coddy logo textTech

Befehlsmuster

Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 56 von 70.

Das Command-Muster ist ein Verhaltensmuster, das eine Anfrage in ein eigenständiges Objekt umwandelt, das alle Informationen über die Anfrage enthält. Durch diese Umwandlung kannst du Anfragen als Methodenargumente übergeben, sie in eine Warteschlange stellen, protokollieren oder rückgängig machbare Vorgänge unterstützen.

Das Muster trennt das Objekt, das eine Operation aufruft, von dem Objekt, das weiß, wie sie ausgeführt wird. Es besteht aus vier wesentlichen Komponenten: einer Befehlsschnittstelle, konkreten Befehlen, einem Empfänger (dem Objekt, das die eigentliche Arbeit ausführt) und einem Aufrufer (dem Objekt, das Befehle auslöst).

public interface ICommand
{
    void Execute();
}

public class Light  // Empfänger
{
    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();
}

Der Aufrufer speichert Befehle und führt sie aus, ohne zu wissen, was sie tun:

public class RemoteControl  // Aufrufer
{
    private ICommand _command;
    
    public void SetCommand(ICommand command) => _command = command;
    
    public void PressButton() => _command.Execute();
}

// Verwendung
var light = new Light();
var remote = new RemoteControl();

remote.SetCommand(new TurnOnCommand(light));
remote.PressButton();  // Light ist AN

remote.SetCommand(new TurnOffCommand(light));
remote.PressButton();  // Light ist AUS

Das Command-Muster ist besonders leistungsfähig für die Implementierung der Rückgängig-Funktion, die Aufzeichnung von Makros oder das Einreihen von Vorgängen zur späteren Ausführung. Jeder Befehl kapselt alles, was zum Ausführen einer Aktion erforderlich ist, wodurch dein System flexibler und erweiterbarer wird.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Texteditor-Befehlssystem mithilfe des Command-Musters. Du erstellst ein System, in dem Bearbeitungsvorgänge wie das Einfügen und Löschen von Text als Befehlsobjekte gekapselt werden, sodass der Editor sie über eine einheitliche Schnittstelle ausführen kann.

Du organisierst deinen Code über drei Dateien:

  • Command.cs: Definiere eine ICommand-Schnittstelle im Namespace TextEditor mit einer einzigen Methode Execute(). Erstelle anschließend zwei konkrete Befehlsklassen:
    • InsertCommand – nimmt in seinem Konstruktor ein Document und einen String text entgegen. Bei der Ausführung hängt er den Text an das Dokument an und gibt Inserted: {text} aus.
    • DeleteCommand – nimmt in seinem Konstruktor ein Document und eine int count entgegen. Bei der Ausführung entfernt er die letzten count Zeichen aus dem Dokument und gibt Deleted: {count} characters aus.
  • Document.cs: Erstelle eine Document-Klasse im selben Namespace. Dies ist dein Empfänger – das Objekt, das die Textoperationen tatsächlich ausführt. Es sollte Folgendes enthalten:
    • Ein privates String-Feld zum Speichern des Inhalts (mit einer leeren Zeichenfolge initialisieren)
    • Eine Append(string text)-Methode, die Text an den Inhalt anhängt
    • Eine RemoveLast(int count)-Methode, die die letzten count Zeichen entfernt (wenn count die Inhaltslänge überschreitet, den gesamten Inhalt löschen)
    • Eine GetContent()-Methode, die den aktuellen Inhalt zurückgibt
  • Program.cs: Erstelle eine Editor-Klasse, die als Aufrufer fungiert. Sie sollte eine SetCommand(ICommand command)-Methode und eine ExecuteCommand()-Methode besitzen, die den aktuellen Befehl ausführt. Zeige in deinem Hauptcode das Command-Muster, indem du eine Reihe von Bearbeitungsvorgängen verarbeitest.

Du erhältst die folgenden Eingaben:

  • Anzahl der auszuführenden Befehle
  • Für jeden Befehl: der Befehlstyp (insert oder delete), gefolgt von dem einzufügenden Text oder der Anzahl der zu löschenden Zeichen

Nachdem alle Befehle ausgeführt wurden, gib den endgültigen Dokumentinhalt in einer neuen Zeile im Format Content: {content} aus.

Wenn die Eingaben beispielsweise folgendermaßen lauten:

4
insert
Hello
insert
 World
delete
3
insert
!

Die Ausgabe sollte folgendermaßen aussehen:

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

Beachte, dass der Editor (Aufrufer) nichts über die Textmanipulation weiß – er führt einfach den Befehl aus, der ihm übergeben wird. Die Befehle kapseln sowohl die Aktion als auch den Empfänger, wodurch sich problemlos neue Operationen wie ReplaceCommand hinzufügen lassen, ohne den Editor zu ändern!

Probier es selbst

using System;
using TextEditor;

// TODO: Erstelle die Editor-Klasse (den Invoker)
public class Editor
{
    // TODO: Füge ein privates Feld hinzu, um den aktuellen Befehl zu speichern
    private ICommand _command;

    // TODO: Implementiere die SetCommand-Methode
    public void SetCommand(ICommand command)
    {
        // TODO: Speichere den Befehl
    }

    // TODO: Implementiere die ExecuteCommand-Methode
    public void ExecuteCommand()
    {
        // TODO: Führe den aktuellen Befehl aus
    }
}

class Program
{
    public static void Main(string[] args)
    {
        // Lies die Anzahl der Befehle ein
        int n = Convert.ToInt32(Console.ReadLine());

        // Erstelle das Dokument (Receiver)
        Document document = new Document();

        // Erstelle den Editor (Invoker)
        Editor editor = new Editor();

        // TODO: Verarbeite jeden Befehl
        for (int i = 0; i < n; i++)
        {
            string commandType = Console.ReadLine();

            // TODO: Erstelle basierend auf commandType den entsprechenden Befehl
            // - Wenn "insert": Lies den Text und erstelle einen InsertCommand
            // - Wenn "delete": Lies die Anzahl und erstelle einen DeleteCommand
            // Setze dann den Befehl im Editor und führe ihn aus
        }

        // TODO: Gib den finalen Inhalt im Format "Content: {content}" aus
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C#-Compiler