Design Patterns: Chain of Responsibility Pattern trong TypeScript 😊 (Series: Bón hành TypeScript - PHẦN 4)
Cách sử dụng Chain of Responsibility bằng TypeScript để giải quyết các vấn đề thực tế trong các project web.
Chào mừng bạn đến với loạt bài Design Patterns trong TypeScript, loạt bài này mình sẽ giới thiệu một số Design Patterns hữu ích trong phát triển web bằng TypeScript.
Các Design Patterns rất quan trọng đối với các web developer và chúng ta có thể code tốt hơn bằng cách thành thạo chúng. Trong bài viết này, mình sẽ sử dụng TypeScript để giới thiệu Chain of Responsibility.
Các Design Patterns rất quan trọng đối với các Dev web và chúng ta có thể good code hơn bằng cách thành thạo chúng. Trong bài viết này, mình sẽ sử dụng TypeScript để giới thiệu Chain of Responsibility .
Chain of Responsibility
Chain of Responsibility là một cách để tránh ghép nối giữa sender
và receiver
của các request bằng cách cho nhiều đối tượng xử lý request. Trong Chain of Responsibility, nhiều đối tượng được kết nối bằng một tham chiếu từ mỗi đối tượng đến đối tượng tiếp theo của nó để tạo thành một chuỗi (next,next,next...). Các request được truyền dọc theo chuỗi cho đến khi một trong các đối tượng trong chuỗi quyết định xử lý request.
Các vị trí khác nhau trong công ty có trách nhiệm và quyền hạn khác nhau. Lấy ví dụ về quy trình nghỉ của một công ty, khi xin nghỉ chỉ cần được sự đồng ý của tổ trưởng, không cần phải chuyển cho cấp trên và giám đốc. Nếu một liên kết trong Chain of Responsibility không thể xử lý request hiện tại, nếu có liên kết tiếp theo, request sẽ được chuyển tiếp đến liên kết tiếp theo để xử lý.
Trong quá trình phát triển phần mềm, đối với Chain of Responsibility, một kịch bản ứng dụng phổ biến là middleware. Chúng ta hãy xem cách sử dụng Chain of Responsibility để xử lý các request.
Để hiểu rõ hơn về đoạn code sau, trước tiên chúng ta hãy xem sơ đồ UML tương ứng:
Trong hình trên, chúng ta xác định một Interface Handler
. Hai hàm sau đây được định nghĩa trong Interface này:
- use(h: Handler): Handler => Dùng để đăng ký handler (middleware)
- get(url: string, callback: (data: any) => void): void => Đăng ký get request handler
Handler interface
interface Handler {
use(h: Handler): Handler;
get(url: string, callback: (data: any) => void): void;
}
Sau đó, chúng ta định nghĩa một abstract Class AbstractHandler
, gói gọn logic xử lý của Chain of Responsibility. Tức là kết hợp các trình xử lý khác nhau để tạo thành một chuỗi tham chiếu.
AbstractHandler abstract class
abstract class AbstractHandler implements Handler {
next!: Handler;
use(h: Handler) {
this.next = h;
return this.next;
}
get(url: string, callback: (data: any) => void) {
if (this.next) {
return this.next.get(url, callback);
}
}
}
Dựa trên abstract Class AbstractHandler
, chúng ta định nghĩa AuthMiddleware
và LoggerMidddleware
tương ứng. AuthMiddleware
middleware được sử dụng để xử lý authentication user và LoggerMidddleware
middleware được sử dụng để ghi log cho từng request.
AuthMiddleware class
class AuthMiddleware extends AbstractHandler {
isAuthenticated: boolean;
constructor(username: string, password: string) {
super();
this.isAuthenticated = false;
if (username === "bytefer" && password === "666") {
this.isAuthenticated = true;
}
}
get(url: string, callback: (data: any) => void) {
if (this.isAuthenticated) {
return super.get(url, callback);
} else {
throw new Error("Not Authorized");
}
}
}
LoggerMiddleware class
class LoggerMiddleware extends AbstractHandler {
get(url: string, callback: (data: any) => void) {
console.log(`Request url is: ${url}`);
return super.get(url, callback);
}
}
Với middleware AuthMiddleware
và LoggerMidddleware
, hãy định nghĩa một Route class
để đăng ký các middleware này.
Route class
class Route extends AbstractHandler {
urlDataMap: { [key: string]: any };
constructor() {
super();
this.urlDataMap = {
"/api/todos": [
{ title: "Learn Design Pattern" },
],
"/api/random": () => Math.random(),
};
}
get(url: string, callback: (data: any) => void) {
super.get(url, callback);
if (this.urlDataMap.hasOwnProperty(url)) {
const value = this.urlDataMap[url];
const result = typeof value === "function" ? value() : value;
callback(result);
}
}
}
Sau khi định nghĩa Route
Route class, chúng ta có thể sử dụng nó và đăng ký các middleware theo cách sau:
const route = new Route();
route.use(new AuthMiddleware("bytefer", "666"))
.use(new LoggerMiddleware());
route.get("/api/todos", (data) => {
console.log(JSON.stringify({ data }, null, 2));
});
route.get("/api/random", (data) => {
console.log(data);
});
Khi bạn chạy thành công đoạn code trên, output tương ứng được hiển thị trong hình sau:
Các tình huống sử dụng của Chain of Responsibility:
- Muốn gửi request tới một trong nhiều đối tượng mà không chỉ định rõ ràng đối tượng nhận request.
- Có nhiều đối tượng có thể xử lý một request và đối tượng nào xử lý request được xác định tự động trong thời gian chạy và Client chỉ cần gửi request đến Chain mà thôi.
Mình hy vọng bạn thích bài viết này và học thêm được điều gì đó mới.
Donate mình một ly cafe hoặc 1 cây bút bi để mình có thêm động lực cho ra nhiều bài viết hay và chất lượng hơn trong tương lai nhé. À mà nếu bạn có bất kỳ câu hỏi nào thì đừng ngại comment hoặc liên hệ mình qua: Zalo - 0374226770 hoặc Facebook. Mình xin cảm ơn.
Momo: NGUYỄN ANH TUẤN - 0374226770
TPBank: NGUYỄN ANH TUẤN - 0374226770 (hoặc 01681423001)
All rights reserved