Skip to main content

Command Palette

Search for a command to run...

Hướng dẫn State Pattern trong Java

Published
5 min readView as Markdown

1. Giới thiệu State Pattern

State Pattern là một mẫu thiết kế thuộc nhóm Behavioral Patterns, cho phép một đối tượng thay đổi hành vi của nó khi trạng thái nội tại của nó thay đổi. Mẫu thiết kế này giúp quản lý trạng thái và hành vi của đối tượng một cách rõ ràng và dễ bảo trì.

2. Các trường hợp ứng dụng State Pattern

  • Quản lý trạng thái phức tạp: Khi một đối tượng có nhiều trạng thái và hành vi của nó phụ thuộc vào các trạng thái này.

  • Chuyển đổi trạng thái động: Khi cần chuyển đổi trạng thái của đối tượng một cách linh hoạt tại thời điểm chạy.

  • Tách biệt logic trạng thái: Khi cần tách biệt logic xử lý của từng trạng thái để dễ bảo trì và mở rộng.

3. Triển khai State Pattern

3.1. Ví dụ triển khai đơn giản

Giả sử chúng ta có một đối tượng Context đại diện cho một máy bán hàng tự động với các trạng thái khác nhau như NoCoinState, HasCoinState, SoldState, và SoldOutState.

// Bước 1: Tạo interface State
public interface State {
    void insertCoin();
    void ejectCoin();
    void dispense();
}

// Bước 2: Tạo các lớp trạng thái cụ thể
public class NoCoinState implements State {
    private VendingMachine vendingMachine;

    public NoCoinState(VendingMachine vendingMachine) {
        this.vendingMachine = vendingMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("Coin inserted.");
        vendingMachine.setState(vendingMachine.getHasCoinState());
    }

    @Override
    public void ejectCoin() {
        System.out.println("No coin to eject.");
    }

    @Override
    public void dispense() {
        System.out.println("Insert coin first.");
    }
}

public class HasCoinState implements State {
    private VendingMachine vendingMachine;

    public HasCoinState(VendingMachine vendingMachine) {
        this.vendingMachine = vendingMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("Coin already inserted.");
    }

    @Override
    public void ejectCoin() {
        System.out.println("Coin ejected.");
        vendingMachine.setState(vendingMachine.getNoCoinState());
    }

    @Override
    public void dispense() {
        System.out.println("Dispensing product.");
        vendingMachine.setState(vendingMachine.getSoldState());
    }
}

public class SoldState implements State {
    private VendingMachine vendingMachine;

    public SoldState(VendingMachine vendingMachine) {
        this.vendingMachine = vendingMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("Please wait, dispensing in progress.");
    }

    @Override
    public void ejectCoin() {
        System.out.println("Cannot eject coin after dispensing.");
    }

    @Override
    public void dispense() {
        System.out.println("Dispensing product.");
        if (vendingMachine.getProductCount() > 0) {
            vendingMachine.setState(vendingMachine.getNoCoinState());
        } else {
            System.out.println("Out of stock.");
            vendingMachine.setState(vendingMachine.getSoldOutState());
        }
    }
}

public class SoldOutState implements State {
    private VendingMachine vendingMachine;

    public SoldOutState(VendingMachine vendingMachine) {
        this.vendingMachine = vendingMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("Out of stock.");
    }

    @Override
    public void ejectCoin() {
        System.out.println("No coin to eject.");
    }

    @Override
    public void dispense() {
        System.out.println("Out of stock.");
    }
}

// Bước 3: Tạo lớp Context
public class VendingMachine {
    private State noCoinState;
    private State hasCoinState;
    private State soldState;
    private State soldOutState;

    private State currentState;
    private int productCount;

    public VendingMachine(int productCount) {
        noCoinState = new NoCoinState(this);
        hasCoinState = new HasCoinState(this);
        soldState = new SoldState(this);
        soldOutState = new SoldOutState(this);

        this.productCount = productCount;
        currentState = productCount > 0 ? noCoinState : soldOutState;
    }

    public void insertCoin() {
        currentState.insertCoin();
    }

    public void ejectCoin() {
        currentState.ejectCoin();
    }

    public void dispense() {
        currentState.dispense();
    }

    public void setState(State state) {
        currentState = state;
    }

    public State getNoCoinState() {
        return noCoinState;
    }

    public State getHasCoinState() {
        return hasCoinState;
    }

    public State getSoldState() {
        return soldState;
    }

    public State getSoldOutState() {
        return soldOutState;
    }

    public int getProductCount() {
        return productCount;
    }

    public void releaseProduct() {
        if (productCount > 0) {
            productCount--;
        }
    }
}

// Bước 4: Sử dụng State Pattern
public class StatePatternDemo {
    public static void main(String[] args) {
        VendingMachine vendingMachine = new VendingMachine(5);

        vendingMachine.insertCoin();
        vendingMachine.dispense();

        vendingMachine.insertCoin();
        vendingMachine.ejectCoin();
        vendingMachine.dispense();
    }
}

3.2. Ví dụ triển khai phức tạp

Giả sử chúng ta có một hệ thống quản lý đơn hàng với các trạng thái khác nhau như NewOrderState, ProcessingState, ShippedState, và DeliveredState.

// Bước 1: Tạo interface State
public 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ể
public class NewOrderState implements OrderState {
    @Override
    public void next(OrderContext context) {
        context.setState(new ProcessingState());
    }

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

    @Override
    public void printStatus() {
        System.out.println("Order placed, not processed yet.");
    }
}

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

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

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

public 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 shipped to delivery address.");
    }
}

public 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 delivered to customer.");
    }
}

// Bước 3: Tạo lớp Context
public class OrderContext {
    private OrderState state;

    public OrderContext() {
        state = new NewOrderState();
    }

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

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

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

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

// Bước 4: Sử dụng State Pattern
public class StatePatternDemo {
    public static void main(String[] args) {
        OrderContext context = new OrderContext();

        context.printStatus();
        context.next();
        context.printStatus();
        context.next();
        context.printStatus();
        context.next();
        context.printStatus();
        context.prev();
        context.printStatus();
    }
}

4. Phân tích các trường hợp ứng dụng State Pattern

4.1. Quản lý trạng thái phức tạp

  • Ưu điểm: Giúp quản lý các trạng thái phức tạp của đối tượng một cách rõ ràng và dễ bảo trì.

  • Nhược điểm: Cần tạo nhiều lớp trạng thái, có thể làm tăng độ phức tạp của hệ thống.

4.2. Chuyển đổi trạng thái động

  • Ưu điểm: Cho phép chuyển đổi trạng thái của đối tượng một cách linh hoạt tại thời điểm chạy.

  • Nhược điểm: Cần đảm bảo rằng các trạng thái được quản lý và chuyển đổi một cách nhất quán.

4.3. Tách biệt logic trạng thái

  • Ưu điểm: Giúp tách biệt logic xử lý của từng trạng thái, dễ dàng bảo trì và mở rộng.

  • Nhược điểm: Cần thiết kế các lớp trạng thái một cách cẩn thận để tránh xung đột và lỗi xử lý.

More from this blog

hoangkim

366 posts