State pattern là một trong những mẫu thiết kế thuộc nhóm Behavioral Patterns, giúp đối tượng thay đổi hành vi của mình khi trạng thái nội bộ thay đổi. Dưới đây là hướng dẫn chi tiết và áp dụng .

1. What (State pattern là gì?)

State pattern cho phép một đối tượng thay đổi hành vi của nó khi trạng thái nội bộ thay đổi mà không cần thay đổi mã nguồn. Mẫu này phân chia logic của các trạng thái vào các lớp trạng thái riêng biệt, và đối tượng chính sẽ chuyển đổi giữa các trạng thái này khi cần thiết.

2. Why (Tại sao cần dùng State pattern?)

  • Giảm sự phức tạp: Nếu bạn có nhiều trạng thái trong một đối tượng và các hành vi khác nhau phụ thuộc vào trạng thái đó, việc viết nhiều câu lệnh if hoặc switch để kiểm tra trạng thái sẽ làm cho mã trở nên phức tạp và khó bảo trì.
  • Dễ dàng mở rộng: Khi cần thêm trạng thái mới, bạn chỉ cần tạo một lớp mới mà không phải thay đổi logic hiện có.
  • Tăng tính bảo trì: Các hành vi phụ thuộc trạng thái được tách riêng, dễ bảo trì và kiểm thử hơn.

3. When (Khi nào nên dùng State pattern?)

  • Khi bạn có một đối tượng có nhiều trạng thái khác nhau và hành vi của nó thay đổi dựa trên trạng thái hiện tại.
  • Khi bạn muốn tránh việc sử dụng nhiều câu lệnh điều kiện (if, switch) để kiểm tra trạng thái trong các phương thức.
  • Khi bạn cần thêm mới hoặc thay đổi hành vi của đối tượng mà không muốn làm ảnh hưởng đến logic hiện tại.

4. How (Cách triển khai State pattern)

State pattern thường bao gồm các thành phần sau:

  • Context: Đối tượng chính chứa trạng thái và hoạt động.
  • State Interface: Định nghĩa các hành vi mà mỗi trạng thái phải thực hiện.
  • Concrete State Classes: Các lớp cụ thể triển khai hành vi khác nhau cho từng trạng thái.

Các bước triển khai:

  1. Tạo một interface hoặc abstract class đại diện cho các trạng thái (State).
  2. Tạo các lớp con để định nghĩa hành vi cụ thể cho từng trạng thái.
  3. Tạo Context class chứa tham chiếu đến một đối tượng trạng thái, và có các phương thức để thay đổi hành vi của đối tượng bằng cách thay đổi trạng thái.

5. Demo tính năng quản lý đơn hàng Shopee

Chúng ta sẽ xây dựng một hệ thống quản lý đơn hàng trực tuyến với các trạng thái:

  • Processing (Đang xử lý)
  • Shipped (Đang vận chuyển)
  • Delivered (Đã giao hàng)

Bước 1: Tạo interface OrderState

interface OrderState {
    void next(OrderContext context);
    void prev(OrderContext context);
    void printStatus();
}

Bước 2: Tạo các lớp trạng thái cụ thể
Trạng thái Đang xử lý (Processing)

class ProcessingState implements OrderState {
    @Override
    public void next(OrderContext context) {
        context.setState(new ShippedState());
    }

    @Override
    public void prev(OrderContext context) {
        System.out.println("The order is in its initial state.");
    }

    @Override
    public void printStatus() {
        System.out.println("Order is being processed.");
    }
}

Trạng thái Đang vận chuyển (Shipped)

class ShippedState implements OrderState {
    @Override
    public void next(OrderContext context) {
        context.setState(new DeliveredState());
    }

    @Override
    public void prev(OrderContext context) {
        context.setState(new ProcessingState());
    }

    @Override
    public void printStatus() {
        System.out.println("Order has been shipped.");
    }
}

Trạng thái Đã giao hàng (Delivered)

class DeliveredState implements OrderState {
    @Override
    public void next(OrderContext context) {
        System.out.println("This order is already delivered.");
    }

    @Override
    public void prev(OrderContext context) {
        context.setState(new ShippedState());
    }

    @Override
    public void printStatus() {
        System.out.println("Order has been delivered.");
    }
}

Bước 3: Tạo lớp OrderContext để lưu trữ trạng thái

class OrderContext {
    private OrderState state;

    public OrderContext() {
        // Khởi tạo đơn hàng ở trạng thái "Processing"
        state = new ProcessingState();
    }

    public void setState(OrderState state) {
        this.state = state;
    }

    public void nextState() {
        state.next(this);
    }

    public void prevState() {
        state.prev(this);
    }

    public void printStatus() {
        state.printStatus();
    }
}

Bước 4: Client code

public class StatePatternDemo {
    public static void main(String[] args) {
        OrderContext order = new OrderContext();

        order.printStatus(); // Order is being processed.
        order.nextState();

        order.printStatus(); // Order has been shipped.
        order.nextState();

        order.printStatus(); // Order has been delivered.
        order.prevState();

        order.printStatus(); // Order has been shipped.
    }
}

Giải thích ví dụ trên:

  • Processing: Khi đơn hàng đang trong giai đoạn xử lý, bạn không thể quay lại trạng thái trước đó vì đó là trạng thái đầu tiên.
  • Shipped: Khi đơn hàng đã được vận chuyển, bạn có thể quay lại trạng thái “Processing” nếu có vấn đề, hoặc chuyển tiếp đến trạng thái “Delivered” khi hàng đã tới tay khách hàng.
  • Delivered: Khi đơn hàng đã giao xong, không thể chuyển về trạng thái trước đó mà chỉ có thể xem trạng thái hiện tại là “Delivered”.

6. Summary (Tổng kết)

  • State pattern giúp mô phỏng các trạng thái của một đối tượng, trong ví dụ này là đơn đặt hàng. Khi trạng thái thay đổi, hành vi cũng thay đổi tương ứng mà không cần thay đổi logic chung.

  • Ứng dụng của mẫu này giúp mã dễ bảo trì và mở rộng, đặc biệt trong các hệ thống có nhiều trạng thái phức tạp như quản lý đơn hàng, quy trình làm việc (workflow), hoặc trạng thái máy móc trong sản xuất,…

    status order