Menu
CoddyTech

Mẫu trạng thái

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 98 trên 110.

Mẫu State cho phép một đối tượng thay đổi hành vi khi trạng thái bên trong thay đổi, khiến đối tượng trông như thể đã đổi lớp. Thay vì dùng các câu lệnh điều kiện phức tạp để xử lý những trạng thái khác nhau, bạn đóng gói mỗi trạng thái trong lớp riêng và ủy quyền hành vi cho đối tượng trạng thái hiện tại.

Mẫu này gồm một Context giữ tham chiếu đến trạng thái hiện tại và các lớp State định nghĩa hành vi cho từng trạng thái có thể có. Khi trạng thái của context thay đổi, hành vi của nó cũng tự động thay đổi:

abstract class DocumentState {
  void publish(Document doc);
  String getStatus();
}

class DraftState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Moving to review...');
    doc.setState(ReviewState());
  }

  @override
  String getStatus() => 'Draft';
}

class ReviewState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Document published!');
    doc.setState(PublishedState());
  }

  @override
  String getStatus() => 'Under Review';
}

class PublishedState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Already published.');
  }

  @override
  String getStatus() => 'Published';
}

class Document {
  DocumentState _state = DraftState();

  void setState(DocumentState state) => _state = state;
  void publish() => _state.publish(this);
  String getStatus() => _state.getStatus();
}

void main() {
  var doc = Document();
  print(doc.getStatus());  // Draft
  doc.publish();           // Moving to review...
  print(doc.getStatus());  // Under Review
  doc.publish();           // Document published!
  print(doc.getStatus());  // Published
}

Mỗi lớp (class) trạng thái xử lý hành động publish() theo cách khác nhau và có thể chuyển tài liệu sang trạng thái tiếp theo. Lớp Document không cần câu lệnh điều kiện để kiểm tra trạng thái hiện tại, nó chỉ cần giao việc đó cho đối tượng trạng thái đang hoạt động. Mẫu này phù hợp với các đối tượng có những chế độ hoạt động riêng biệt, như xử lý đơn hàng, trình phát đa phương tiện hoặc hệ thống quy trình làm việc.

challenge icon

Thử thách

Dễ

Hãy cùng xây dựng hệ thống đèn giao thông bằng mẫu State! Bạn sẽ tạo một đèn giao thông luân chuyển qua các trạng thái khác nhau, trong đó mỗi trạng thái quyết định màu đèn và cách chuyển sang trạng thái tiếp theo.

Bạn sẽ sắp xếp code thành hai tệp:

  • traffic_light.dart: Tệp này chứa các lớp trạng thái và ngữ cảnh đèn giao thông. Tạo lớp trừu tượng TrafficLightState với hai phương thức: String getColor() trả về màu đèn hiện tại và void next(TrafficLight light) chuyển đèn sang trạng thái tiếp theo. Triển khai ba lớp trạng thái cụ thể:
    • RedState: trả về RED làm màu và in ra Stop! Light is red. khi gọi next(), sau đó chuyển sang GreenState
    • GreenState: trả về GREEN làm màu và in ra Go! Light is green. khi gọi next(), sau đó chuyển sang YellowState
    • YellowState: trả về YELLOW làm màu và in ra Caution! Light is yellow. khi gọi next(), sau đó chuyển sang RedState
    Tiếp theo, tạo lớp TrafficLight (ngữ cảnh), bắt đầu ở trạng thái RedState. Lớp này cần có phương thức setState() để đổi trạng thái hiện tại, phương thức getColor() ủy quyền cho trạng thái hiện tại và phương thức change() gọi next() trên trạng thái hiện tại.
  • main.dart: Nhập tệp đèn giao thông và minh họa mẫu State đang hoạt động. Tạo một TrafficLight và in ra màu ban đầu. Sau đó gọi change() ba lần, mỗi lần đều in ra màu sau khi đổi. Như vậy, bạn sẽ thấy đèn luân chuyển qua tất cả các trạng thái rồi quay lại trạng thái ban đầu.

Hãy chú ý rằng lớp TrafficLight không cần câu lệnh điều kiện để xác định hành vi. Mỗi trạng thái tự biết màu của nó và trạng thái nào sẽ đến tiếp theo. Đèn giao thông chỉ cần ủy quyền cho trạng thái đang hoạt động!

Đầu ra dự kiến:

RED
Stop! Light is red.
GREEN
Go! Light is green.
YELLOW
Caution! Light is yellow.
RED

Tự làm thử

import 'traffic_light.dart';

void main() {
  // TODO: Tạo một instance của TrafficLight
  
  // TODO: In ra màu ban đầu
  
  // TODO: Gọi change() và in ra màu (3 lần để đi qua tất cả các trạng thái)
  // Lần chuyển thứ nhất: RED -> GREEN
  
  // Lần chuyển thứ hai: GREEN -> YELLOW
  
  // Lần chuyển thứ ba: YELLOW -> RED
}
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