0
0
Lập trình
Flame Kris
Flame Krisbacodekiller

Áp dụng mẫu thiết kế Chain of Responsibility trong dự án: Hướng dẫn chi tiết với Apache Commons Chain

Đăng vào 4 ngày trước

• 6 phút đọc

Giới thiệu mẫu thiết kế Chain of Responsibility

Mẫu thiết kế Chain of Responsibility (Chuỗi Trách Nhiệm) là một trong những mẫu thiết kế phần mềm phổ biến, giúp xây dựng các ứng dụng mở rộng dễ dàng. Mẫu thiết kế này cho phép tổ chức các bước xử lý thành một chuỗi, với mỗi bước (handler) có thể tái sử dụng và có thể xử lý yêu cầu thông qua việc truyền thông tin giữa các bước.

Một trong những công cụ hữu ích để thực thi mẫu thiết kế này là Apache Commons Chain, một framework hỗ trợ việc xây dựng chuỗi xử lý trong Java.

Mục đích của Apache Commons Chain

Framework này hỗ trợ phát triển các ứng dụng có khả năng mở rộng cao, nơi mà các bước xử lý được liên kết chặt chẽ với nhau, cho phép ứng dụng dễ dàng được mở rộng và bảo trì.

Các thành phần chính của Apache Commons Chain

Trong Apache Commons Chain, lớp ChainBase là cốt lõi, cung cấp triển khai mặc định cho interface Chain. Nó cho phép chúng ta tạo ra chuỗi các lệnh (commands), trong đó mỗi lệnh sẽ xử lý một phần của yêu cầu. Một chain có thể được cấu hình để tiếp tục hoặc dừng xử lý tùy thuộc vào kết quả của từng lệnh.

1. Interface Command

Tất cả các lệnh trong chuỗi cần phải triển khai interface này và ghi đè phương thức execute.

2. Interface Chain

Interface này đại diện cho danh sách các Command đã được cấu hình và sẽ thực thi theo thứ tự, xử lý trên một ngữ cảnh nhất định (Context).

3. Lớp ChainBase

ChainBase triển khai Chain và cung cấp logic để thực thi các lệnh theo thứ tự đã định.

Ví dụ sử dụng ChainBase

Dưới đây là một ví dụ cụ thể để minh họa cách sử dụng ChainBase:

java Copy
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.impl.ChainBase;
import org.apache.commons.chain.impl.ContextBase;

public class AuthCommand implements Command {
    @Override
    public boolean execute(Context context) {
        System.out.println("Xác thực request...");
        // Nếu xác thực thất bại, có thể trả về true để dừng chain
        return false; // Tiếp tục chain
    }
}

public class LoggingCommand implements Command {
    @Override
    public boolean execute(Context context) {
        System.out.println("Ghi log request...");
        return false; // Tiếp tục chain
    }
}

public class BusinessLogicCommand implements Command {
    @Override
    public boolean execute(Context context) {
        System.out.println("Xử lý nghiệp vụ...");
        return false; // Tiếp tục chain
    }
}

public class ChainExample {
    public static void main(String[] args) throws Exception {
        // Tạo một context
        Context context = new ContextBase();

        // Tạo một chain
        ChainBase chain = new ChainBase();
        chain.addCommand(new AuthCommand());
        chain.addCommand(new LoggingCommand());
        chain.addCommand(new BusinessLogicCommand());

        // Thực thi chuỗi
        chain.execute(context);
    }
}

Trong ví dụ trên, chúng ta đã tạo ra các lệnh khác nhau như AuthCommand, LoggingCommandBusinessLogicCommand. Mỗi lệnh này xử lý một nhiệm vụ riêng biệt trong quá trình xử lý yêu cầu.

Xây dựng ProcessContext

Trong một dự án thực tế, để quản lý tốt hơn giữa các Command trong một chain, chúng ta có thể tạo ra một lớp ProcessContext kế thừa từ ContextBase. Trong lớp này, chúng ta có thể định nghĩa các thuộc tính cần thiết như:

  • Request
  • Response
  • Result
  • Cust
  • Và các biến tùy chỉnh khác, chẳng hạn như `HashMap<String, Object> varRef;

Tách bạch các Service

Để đảm bảo tính SOLID, chúng ta có thể tách các bước xử lý thành các dịch vụ riêng biệt và sử dụng Spring Boot để tiêm chúng vào dịch vụ chính thông qua annotation @Autowired. Dưới đây là một ví dụ:

java Copy
@Service
public class DoCheckRefNo {
    public boolean execute(ProcessContext processContext) {
        System.out.println("Đang kiểm tra RefNo...");
        return processContext.getResult().isOk(); // Ví dụ đơn giản
    }
}

@Service
public class CheckCustomerState {
    public boolean execute(ProcessContext processContext) {
        System.out.println("Đang kiểm tra trạng thái khách hàng...");
        return processContext.getResult().isOk(); // Ví dụ đơn giản
    }
}

@Service
public class DoCheckMsisdnEmail {
    public boolean execute(ProcessContext processContext) {
        System.out.println("Đang kiểm tra Msisdn và Email...");
        return processContext.getResult().isOk(); // Ví dụ đơn giản
    }
}

@Service
public class CheckSRVCPCCDCustomer {
    public boolean execute(ProcessContext processContext) {
        System.out.println("Đang kiểm tra khách hàng SRVC PCCD...");
        return processContext.getResult().isOk(); // Ví dụ đơn giản
    }
}

Lớp chính CheckProcess sẽ quản lý việc thực hiện các lệnh này:

java Copy
@Service
public class CheckProcess {
    private final DoCheckRefNo checkRefNo;
    private final CheckCustomerState checkCustomerState;
    private final DoCheckMsisdnEmail doCheckMsisdnEmail;
    private final CheckSRVCPCCDCustomer checkSRVCPCCDCustomer;

    @Autowired
    public CheckProcess(DoCheckRefNo checkRefNo, 
                        CheckCustomerState checkCustomerState,
                        DoCheckMsisdnEmail doCheckMsisdnEmail,
                        CheckSRVCPCCDCustomer checkSRVCPCCDCustomer) {
        this.checkRefNo = checkRefNo;
        this.checkCustomerState = checkCustomerState;
        this.doCheckMsisdnEmail = doCheckMsisdnEmail;
        this.checkSRVCPCCDCustomer = checkSRVCPCCDCustomer;
    }

    public void executeProcess(ProcessContext processContext) {
        boolean checkResult;

        // Kiểm tra RefNo
        checkResult = checkRefNo.execute(processContext);
        if (!processContext.getResult().isOk()) return;

        // Kiểm tra trạng thái khách hàng
        checkResult = checkCustomerState.execute(processContext);
        if (!processContext.getResult().isOk()) return;

        // Kiểm tra Msisdn và Email
        checkResult = doCheckMsisdnEmail.execute(processContext);
        if (!processContext.getResult().isOk()) return;

        // Kiểm tra khách hàng SRVC PCCD
        checkResult = checkSRVCPCCDCustomer.execute(processContext);
        if (!processContext.getResult().isOk()) return;

        System.out.println("Tất cả các bước kiểm tra đã hoàn thành thành công.");
    }
}

Kỹ thuật gọi Bean theo tên trong chuỗi

Chúng ta cũng có thể sử dụng một kỹ thuật thú vị để gọi Bean mong muốn theo tên và thực thi trong chuỗi này. Điều này giúp cải thiện tính linh hoạt trong quản lý các service:

java Copy
IExecutor<ProcessContext, Boolean> executor = SpringContext.getBean("_nameBean_");
executor.execute(context);
if (!context.getResult().isOk()) return;
java Copy
@Service("_nameBean_")
public class Service implements IExecutor<ProcessContext, Boolean> {
    @Override
    public boolean execute(ProcessContext context) throws Exception {
        return true;
    }
}

Kết luận

Việc áp dụng mẫu thiết kế Chain of Responsibility thông qua Apache Commons Chain mang lại nhiều lợi ích cho việc tổ chức và quản lý các bước xử lý trong ứng dụng. Tuy nhiên, việc sử dụng Spring Boot để tách các dịch vụ thành các service riêng biệt và tiêm chúng vào dịch vụ quản lý chính thông qua @Autowired là một cách tiếp cận tối ưu hơn. Cách này không chỉ giúp mã nguồn trở nên dễ bảo trì mà còn dễ dàng mở rộng trong tương lai. Điều này đặc biệt hữu ích cho các ứng dụng với luồng xử lý phức tạp.
source: viblo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào