Wzorzec polecenia
Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 94 z 110.
Wzorzec Command hermetyzuje żądanie w obiekcie, umożliwiając parametryzowanie klientów różnymi żądaniami, kolejkowanie operacji lub obsługę funkcji cofania. Zamiast bezpośrednio wywoływać metodę, opakowujesz działanie w obiekt polecenia, który można przechowywać, przekazywać dalej lub wykonać później.
Wzorzec ten obejmuje trzy kluczowe elementy: interfejs Command z metodą wykonującą, konkretne polecenia, które implementują określone działania, oraz odbiorcę, który wykonuje właściwą pracę. Opcjonalny wywołujący uruchamia polecenia, nie wiedząc, co robią:
abstract class Command {
void execute();
}
class Light {
void turnOn() => print('Light is ON');
void turnOff() => print('Light is OFF');
}
class TurnOnCommand implements Command {
final Light light;
TurnOnCommand(this.light);
@override
void execute() => light.turnOn();
}
class TurnOffCommand implements Command {
final Light light;
TurnOffCommand(this.light);
@override
void execute() => light.turnOff();
}
class RemoteControl {
Command? _command;
void setCommand(Command command) {
_command = command;
}
void pressButton() {
_command?.execute();
}
}
void main() {
var light = Light();
var remote = RemoteControl();
remote.setCommand(TurnOnCommand(light));
remote.pressButton(); // Light is ON
remote.setCommand(TurnOffCommand(light));
remote.pressButton(); // Light is OFF
}RemoteControl nic nie wie o światłach — po prostu wykonuje otrzymane polecenie. To rozdzielenie ułatwia dodawanie nowych poleceń bez modyfikowania wywołującego. Wzorzec Command idealnie nadaje się do implementowania systemów cofania i ponawiania, kolejek zadań lub nagrywania makr, gdy trzeba traktować działania jako pełnoprawne obiekty.
Wyzwanie
ŁatwyZbudujmy system poleceń dla edytora tekstu, używając wzorca Command! Utworzysz system, który hermetyzuje operacje na tekście jako obiekty poleceń, dzięki czemu edytor może wykonywać różne działania bez znajomości szczegółów każdej operacji. To klasyczne zastosowanie wzorca Command — pomyśl o nim jak o systemie cofania i ponawiania, w którym każde działanie jest przechowywane jako obiekt.
Podzielisz kod na dwa pliki:
commands.dart: Utwórz tutaj system poleceń. Zacznij od klasy abstrakcyjnejCommand, która deklaruje metodęexecute(). Następnie utwórz klasęTextDocument(odbiorcę), która przechowuje poleString content(początkowo puste) i ma trzy metody:append(String text)— dodaje tekst na końcu zawartościclear()— ustawia zawartość na pusty ciąg znakówshow()— wyświetlaDocument: [content]
TextDocument:AppendCommand— w konstruktorze przyjmuje dokument i tekst, a po wykonaniu dołącza tekstClearCommand— w konstruktorze przyjmuje dokument, a po wykonaniu go czyściShowCommand— w konstruktorze przyjmuje dokument, a po wykonaniu wyświetla jego zawartość
TextEditor(inicjatora), która przechowuje listę poleceń. Powinna mieć metodęaddCommand(Command command)służącą do dodawania poleceń do kolejki oraz metodęrunAll(), która wykonuje wszystkie polecenia z kolejki w odpowiedniej kolejności.main.dart: Zaimportuj plik z poleceniami i zademonstruj wzorzec Command. Utwórz obiektTextDocumenti obiektTextEditor. Dodaj do kolejki następujące polecenia w podanej kolejności: dołączHello, dołączWorld, wyświetl dokument, dołącz!, wyświetl ponownie, wyczyść dokument i wyświetl go po raz ostatni. Następnie wykonaj wszystkie polecenia z kolejki.
Zwróć uwagę, że TextEditor nie wie nic o dołączaniu, czyszczeniu ani wyświetlaniu — po prostu wykonuje przekazane mu polecenia. To właśnie istota wzorca Command!
Oczekiwany wynik:
Document: Hello World
Document: Hello World!
Document: Spróbuj swoich sił
import 'commands.dart';
void main() {
// TODO: Utwórz instancję TextDocument
// TODO: Utwórz instancję TextEditor
// TODO: Dodaj poniższe polecenia do kolejki w podanej kolejności:
// 1. Dopisz "Hello"
// 2. Dopisz " World"
// 3. Wyświetl dokument
// 4. Dopisz "!"
// 5. Wyświetl dokument ponownie
// 6. Wyczyść dokument
// 7. Wyświetl dokument po raz ostatni
// TODO: Wykonaj wszystkie polecenia z kolejki
}
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