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 C# của Coddy. Bài học 60 trên 70.

Mẫu State là một mẫu hành vi cho phép đối tượng thay đổi hành vi khi trạng thái bên trong thay đổi. 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 ba thành phần: một giao diện trạng thái xác định hành vi riêng của từng trạng thái, các lớp trạng thái cụ thể triển khai hành vi đó và một lớp ngữ cảnh duy trì tham chiếu đến trạng thái hiện tại:

public interface IDocumentState
{
    void Publish(Document doc);
}

public class DraftState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Moving to moderation");
        doc.SetState(new ModerationState());
    }
}

public class ModerationState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Publishing document");
        doc.SetState(new PublishedState());
    }
}

public class PublishedState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Already published");
    }
}

Đối tượng ngữ cảnh lưu trạng thái hiện tại và ủy quyền các thao tác cho trạng thái đó. Các đối tượng trạng thái có thể kích hoạt chuyển đổi bằng cách gọi SetState() trên đối tượng ngữ cảnh:

public class Document
{
    private IDocumentState _state = new DraftState();
    
    public void SetState(IDocumentState state) => _state = state;
    
    public void Publish() => _state.Publish(this);
}

var doc = new Document();
doc.Publish();  // Chuyển sang trạng thái chờ duyệt
doc.Publish();  // Xuất bản tài liệu
doc.Publish();  // Đã xuất bản

Mẫu trạng thái (State pattern) loại bỏ các câu lệnh if-else hoặc switch dài dòng dùng để kiểm tra trạng thái hiện tại. Mỗi lớp trạng thái chỉ xử lý hành vi riêng của mình, giúp bạn dễ bảo trì code và mở rộng bằng các trạng thái mới.

challenge icon

Thử thách

Dễ

Hãy xây dựng hệ thống đèn giao thông bằng mẫu State. Đèn giao thông luân phiên qua các trạng thái riêng biệt (đỏ, vàng, xanh lá), và mỗi trạng thái quyết định điều gì xảy ra khi đèn chuyển trạng thái. Thay vì dùng các câu lệnh điều kiện phức tạp, bạn sẽ đóng gói từng trạng thái đèn trong lớp riêng.

Bạn sẽ sắp xếp code trong ba tệp:

  • TrafficLightState.cs: Định nghĩa giao diện ITrafficLightState trong không gian tên Traffic với phương thức Change(TrafficLight light). Sau đó tạo ba lớp trạng thái cụ thể:
    • RedState , khi gọi Change, lớp này in ra Red - Stop! Changing to Green... và chuyển đèn sang GreenState
    • GreenState , in ra Green - Go! Changing to Yellow... và chuyển sang YellowState
    • YellowState , in ra Yellow - Caution! Changing to Red... và chuyển sang RedState
  • TrafficLight.cs: Tạo lớp TrafficLight trong cùng không gian tên. Đây là lớp ngữ cảnh duy trì trạng thái hiện tại. Theo mặc định, lớp bắt đầu ở trạng thái RedState và có:
    • Phương thức SetState(ITrafficLightState state) để các đối tượng trạng thái dùng khi chuyển trạng thái
    • Phương thức Change() ủy quyền cho phương thức Change của trạng thái hiện tại
  • Program.cs: Kết hợp mọi thứ bằng cách tạo một TrafficLight và luân phiên chuyển trạng thái dựa trên đầu vào.

Bạn sẽ nhận một đầu vào:

  • Số lần cần chuyển trạng thái của đèn giao thông (một số nguyên)

Tạo một TrafficLight (ban đầu ở trạng thái đỏ) và gọi Change() số lần đã cho.

Ví dụ, nếu đầu vào là 3, đầu ra sẽ là:

Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...

Nếu đầu vào là 5, đèn sẽ quay lại trạng thái ban đầu:

Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...

Lưu ý rằng lớp TrafficLight không chứa logic về ý nghĩa của từng màu hoặc trạng thái tiếp theo. Tất cả kiến thức đó nằm trong các lớp trạng thái riêng. Mỗi trạng thái chịu trách nhiệm cho hành vi của mình và kích hoạt quá trình chuyển sang trạng thái tiếp theo!

Tự làm thử

using System;
using Traffic;

class Program
{
    public static void Main(String[] args)
    {
        // Đọc số lần chuyển trạng thái đèn giao thông
        int n = Convert.ToInt32(Console.ReadLine());

        // TODO: Tạo một instance TrafficLight (mặc định bắt đầu ở RedState)

        // TODO: Dùng vòng lặp để gọi phương thức (method) Change() n lần
    }
}
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 C# online