Menu
CoddyTech

Mẫu lệnh

Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 94 trên 110.

Mẫu Command đóng gói một yêu cầu thành một đối tượng, cho phép bạn truyền các yêu cầu khác nhau làm tham số cho các bên gọi, xếp hàng các thao tác hoặc hỗ trợ chức năng hoàn tác. Thay vì gọi trực tiếp một phương thức, bạn đóng gói hành động trong một đối tượng lệnh để có thể lưu trữ, truyền đi hoặc thực thi sau.

Mẫu thiết kế này gồm ba thành phần chính: giao diện Command với phương thức execute, Concrete Commands triển khai các hành động cụ thể và Receiver thực hiện công việc thực tế. Một Invoker tùy chọn kích hoạt các lệnh mà không cần biết chúng làm gì:

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();  // Đèn đã bật

  remote.setCommand(TurnOffCommand(light));
  remote.pressButton();  // Đèn đã tắt
}

RemoteControl không biết gì về đèn, nó chỉ thực thi lệnh được giao. Sự tách biệt này giúp bạn dễ dàng thêm lệnh mới mà không cần sửa đổi đối tượng gọi. Mẫu Command rất phù hợp để triển khai hệ thống hoàn tác/làm lại, hàng đợi tác vụ hoặc ghi macro, khi bạn cần xem hành động là các đối tượng hạng nhất.

challenge icon

Thử thách

Dễ

Hãy cùng xây dựng một hệ thống lệnh cho trình soạn thảo văn bản bằng mẫu Command! Bạn sẽ tạo một hệ thống đóng gói các thao tác với văn bản thành đối tượng lệnh, cho phép trình soạn thảo thực hiện nhiều hành động mà không cần biết chi tiết của từng thao tác. Đây là một trường hợp sử dụng kinh điển của mẫu Command, hãy hình dung như hệ thống hoàn tác/làm lại, trong đó mỗi hành động được lưu dưới dạng một đối tượng.

Bạn sẽ sắp xếp code vào hai tệp:

  • commands.dart: Tạo hệ thống lệnh tại đây. Bắt đầu bằng một lớp trừu tượng Command khai báo phương thức execute(). Sau đó, tạo lớp TextDocument (bên nhận) có trường String content (ban đầu để trống) và ba phương thức:
    • append(String text) - thêm văn bản vào cuối nội dung
    • clear() - đặt nội dung thành chuỗi rỗng
    • show() - in ra Document: [content]
    Tiếp theo, triển khai ba lệnh cụ thể hoạt động với TextDocument:
    • AppendCommand - nhận một tài liệu và văn bản trong hàm khởi tạo, rồi thêm văn bản khi được thực thi
    • ClearCommand - nhận một tài liệu trong hàm khởi tạo, rồi xóa nội dung khi được thực thi
    • ShowCommand - nhận một tài liệu trong hàm khởi tạo, rồi hiển thị nội dung khi được thực thi
    Cuối cùng, tạo lớp TextEditor (bên gọi) để lưu danh sách lệnh. Lớp này cần có phương thức addCommand(Command command) để xếp lệnh vào hàng đợi và phương thức runAll() để thực thi tất cả lệnh đã xếp hàng theo đúng thứ tự.
  • main.dart: Nhập tệp lệnh và minh họa mẫu Command. Tạo một TextDocument và một TextEditor. Xếp các lệnh sau vào hàng đợi theo thứ tự: thêm Hello, thêm World, hiển thị tài liệu, thêm !, hiển thị lại, xóa tài liệu rồi hiển thị lần cuối. Sau đó, chạy tất cả lệnh đã xếp hàng.

Hãy để ý rằng TextEditor không biết gì về việc thêm, xóa hay hiển thị. Nó chỉ thực thi những lệnh được giao. Sự tách biệt này chính là cốt lõi của mẫu Command!

Đầu ra dự kiến:

Document: Hello World
Document: Hello World!
Document: 

Tự làm thử

import 'commands.dart';

void main() {
  // TODO: Tạo một instance của TextDocument

  // TODO: Tạo một instance của TextEditor

  // TODO: Xếp các lệnh sau vào hàng đợi theo thứ tự:
  // 1. Thêm "Hello"
  // 2. Thêm " World"
  // 3. Hiển thị tài liệu
  // 4. Thêm "!"
  // 5. Hiển thị lại tài liệu
  // 6. Xóa nội dung tài liệu
  // 7. Hiển thị tài liệu lần cuối

  // TODO: Chạy tất cả lệnh trong hàng đợi
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Dart online