- vừa được xem lúc

Design pattern: Chain of Responsibility áp dụng trong dự án như thế nào?

0 0 8

Người đăng: Ông Huy Thắng

Theo Viblo Asia

Để thực thi mẫu thiết kế này thì đã có 1 framework hỗ trợ việc xây dựng đó là Apache Commons Chain

Mục đích: hỗ trợ việc xây dựng các ứng dụng có khả năng mở rông cao, nơi các bước xử lý được tổ chức thành một chuỗi (chain) và mỗi bước xử lý là một thành phần có thể tái sử dụng (handler)

Lớp ChainBase là một lớp triển khai mặc định của interface Chain trong Apache Commons Chain. Nó cho phép tạo ra một chuỗi các lệnh (commands), nơi mỗi lệnh trong chuỗi 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 ngừng xử lý tùy thuộc vào kết quả của mỗi lệnh.

Cách hoạt động của ChainBase: ChainBase implements Chain trong interface Chain có 2 method là addCommand(void) và execute(boolean)

Các thành phần chính:

  1. Command interface: Tất cả các lệnh trong chuỗi đều phải implements interface này. Sau đó @Override lại phương thức excute
  2. Chain interface: đại diện cho danh sách các Command (lệnh) đã được cấu hình, và sẽ được thực thi theo thứ tự để xử lý trên một Context (ngữ cảnh)
  3. ChainBase lớp triển khai Chain và cung cấp logic để thực thi các lệnh theo thứ tự.

Ví dụ sử dụng ChainBase

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 dự án thực tế, để được xuyên suốt giữa các Command trong 1 Chain, ta tạo ra 1 class ví dụ là ProcessContext extends ContextBase Thường trong lớp này sẽ có 4 đại diện:

  • Request
  • Response
  • Result
  • Cust
  • và các biến khác tùy chỉnh như: HashMap<String, Object> varRef;

Thay vì cách sử dụng trên ta có thể tách ra nhiều Service và Autowired chúng vào. Đảm bảo tính S trong Solid

@Service
public class DoCheckRefNo { public boolean execute(ProcessContext processContext) { // Logic kiểm tra RefNo 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) { // Logic kiểm tra trạng thái khách hàng 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) { // Logic kiểm tra Msisdn và Email 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) { // Logic kiểm tra khách hàng SRVC PCCD System.out.println("Đang kiểm tra khách hàng SRVC PCCD..."); return processContext.getResult().isOk(); // Ví dụ đơn giản }
}
@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."); }
}

**Và còn 1 kỹ thuật rất hay để gọi Bean mong muốn theo tên và thực thi trong chuỗi này. **

Đó là sử dụng

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

Kết luận Thay vì sử dụng ChainBase và tự quản lý chuỗi các lệnh (commands), việc sử dụng Spring Boot để tách các bước xử lý thành các service riêng biệt và tiêm chúng vào service quản lý chính thông qua @Autowired là một cách tiếp cận linh hoạt và dễ kiểm thử hơn. Điều này đặc biệt hữu ích trong các ứng dụng Spring Boot có luồng xử lý phức tạp, vì nó dễ bảo trì và dễ mở rộng hơn trong tương lai.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tổng hợp các bài hướng dẫn về Design Pattern - 23 mẫu cơ bản của GoF

Link bài viết gốc: https://gpcoder.com/4164-gioi-thieu-design-patterns/. Design Patterns là gì. Design Patterns không phải là ngôn ngữ cụ thể nào cả.

0 0 302

- vừa được xem lúc

Giới thiệu về Builder Design Pattern

Nguồn: refactoring.guru. Builder. Ý đồ.

0 0 44

- vừa được xem lúc

Một ví dụ nhỏ về Factory method

Trong bài viết trước mình đã giới thiệu tới các bạn về Abstract Factory pattern, các bạn quan tâm có thể theo dõi lại tại đây. Để tiếp tục về chủ đề design pattern trong bài viết này mình sẽ trình bày những khái niệm, ưu nhược điểm và các sử dụng của một creational design pattern khác đó là Factory

0 0 38

- vừa được xem lúc

Tôi đã dùng Service Pattern trong NuxtJS như thế nào ?

Giới thiệu. Trong quá trình làm VueJS NuxtJS hay thậm chí là Laravel mình cũng hay áp dụng các pattern như Service hoặc Repository.

0 0 69

- vừa được xem lúc

Hướng dẫn Adapter Design Pattern

Trong bài viết này, chúng ta sẽ cùng tìm hiểu về Adapter Design Pattern qua cấu trúc, cánh triển khai, ví dụ, ưu điểm nhược điểm và ứng dụng của nó. Đây là bài viết đầu tiên của mình nên sẽ không trán

1 1 63

- vừa được xem lúc

Giới thiệu về Prototype Design Pattern

Ý đồ. Prototype là một creational design pattern cho phép bạn sao chép các object hiện có mà không làm cho code của bạn phụ thuộc vào các class của chúng.

0 0 52