Blog#59: Design Patterns: Adapter Pattern trong TypeScript 😊 (Series: Bón hành TypeScript – PHẦN 8)

Mình là TUẤN hiện đang là một Full-stack Web Developer tại Tokyo 😊. Nếu bạn thấy Blog này hay xin hãy cho mình một like và đăng ký để ủng hộ mình nhé 😉. Dễ dàng giải quyết các vấn đề về các Interface không tương thích bằng cách sử dụng Adapter Pattern Các Design

image.png

Mình là TUẤN hiện đang là một Full-stack Web Developer tại Tokyo 😊.
Nếu bạn thấy Blog này hay xin hãy cho mình một like và đăng ký để ủng hộ mình nhé 😉.

Dễ dàng giải quyết các vấn đề về các Interface không tương thích bằng cách sử dụng Adapter Pattern

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 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 Adapter Pattern.

Kịch bản thường gặp

Trong hệ thống web, mail service là một dịch vụ được sử dụng rất phổ biến. Trên nền tảng Node.js, chúng ta có thể sử dụng mô-đun nodemailer để dễ dàng implement chức năng gửi email. Sau khi cài đặt thành công mô-đun nodemailer, bạn có thể làm theo các bước bên dưới để gửi email:

let transporter = nodemailer.createTransport(transport[, defaults]);
transporter.sendMail(data[, callback])

Để tránh ràng buộc mail service với một service provider cụ thể, trước khi phát triển mail service, chúng ta xác định Interface liên quan đến mail provider:

interfaceEmailProvider{sendMail(options: EmailOptions): Promise<EmailResponse>;}interfaceEmailOptions{
  to: string | string[];
  subject: string;
  html: string;
  from?: string;
  text?: string;}interfaceEmailResponse{}

Với các Interface này, chúng ta có thể dễ dàng tạo một mail service:

classEmailService{constructor(public emailProvider: EmailProvider){}asyncsendMail(options: EmailOptions): Promise<EmailResponse>{const result =awaitthis.emailProvider.sendMail(options);return result;}}

Hiện tại, giải pháp này không phải không có vấn đề, nhưng nếu một ngày nào đó chúng ta cần sử dụng email cloud service provider của bên thứ ba. Chẳng hạn như sendgrid hoặc mailersend,v.v. Bạn sẽ thấy tên của hàm mà SDK sử dụng để gửi thư là send. Vì vậy, chúng ta tiếp tục và xác định một Interface CloudEmailProvider:

interfaceCloudEmailProvider{send(options: EmailOptions): Promise<EmailResponse>;}

So sánh Interface được xác định trước đó EmailProvider, bạn sẽ thấy vấn đề sau:

Screenshot 2022-12-02 at 23.31.59.png

Do đó, chúng ta không thể trực tiếp sử dụng EmailService để truy cập các email cloud service provider của bên thứ ba. Để giải quyết vấn đề này, có nhiều cách. Hãy xem cách sử dụng Adapter Pattern để giải quyết vấn đề trên.

Adapter Pattern

Mục đích của Adapter Pattern là cho phép hai đối tượng không hoạt động cùng nhau được do Interface không khớp với nhau. Nó giống như chất keo, biến đổi những thứ khác nhau để chúng có thể làm việc cùng nhau.
Hoặc giễ hình dung nhất là khi bạn qua Nhật tất cả ổ cắm đều là đầu dẹt => chúng ta cần một Adapter tương ứng để xử lý việc này.

Trong ví dụ trên Adapter Pattern chứa các vai trò sau:

  • Client(EmailService) : Đối tượng cần sử dụng Target interface;
  • Target(EmailProvider) : Xác định Interface mà Client mong đợi;
  • Adapter(CloudEmailAdapter) : Điều chỉnh Adapter Interface thành Target interface;
  • Adapter(CloudEmailProvider) : Xác định Interface cần được điều chỉnh.

Sau khi lướt qua một số thứ cần tạo để apply Adapter Pattern vào ví dụ này, trước tiên hãy tạo class CloudEmailAdapter:

classCloudEmailAdapterimplementsEmailProvider{constructor(public emailProvider: CloudEmailProvider){}asyncsendMail(options: EmailOptions): Promise<EmailResponse>{const result =this.emailProvider.send(options);return result;}}

Trong đoạn code trên, vì hai Interface của EmailProviderCloudEmailProvider không khớp nhau, chúng ta tạo một class CloudEmailAdapter để giải quyết vấn đề tương thích.

Tiếp theo, chúng ta lấy service sendgrid làm ví dụ để implement SendgridEmailProvider:

import{ MailService }from"@sendgrid/mail";classSendgridEmailProviderimplementsCloudEmailProvider{private sendgridMail: MailService;constructor(private config:{
      apiKey: string;
      from: string;}){this.sendgridMail =newMailService();this.sendgridMail.setApiKey(this.config.apiKey);}asyncsend(options: EmailOptions): Promise<EmailResponse>{const result =awaitthis.sendgridMail.send(options);return result;}}

Hint: Đoạn code trên chỉ để show cho các bạn thấy cách dùng apply Pattern và cần được điều chỉnh cho phù hợp khi được sử dụng trong các project thực tế.

Bây giờ các lớp SendgridEmailProviderCloudEmailAdapter đã được định nghĩa, hãy xem cách sử dụng chúng:

const sendgridMail =newSendgridEmailProvider({
  apiKey:"******",
  from:"bytefer@gmail.com",});const cloudEmailAdapter =newCloudEmailAdapter(sendgridMail);const emailService =newEmailService(cloudEmailAdapter);
emailService.sendMail({
  to:"******",
  subject:"Adapter Design Pattern",
  html:"<h3>Adapter Design Pattern</h3>",
  from:"bytefer@gmail.com",});

=> bay giờ thì cho dù là service nào thì các bạn cũng có thể sử dụng hàm sendMail.

VD ngoài lề: Máy tình thường có Adapter sac => qua Nhật 110V hay về VN 220V… cứ có Adapter sạc thì mọi thứ đều giống nhau chỉ cần thực hiện hành động cắm nó vào ổ điện là xong.

Cuối cùng, các kịch bản sử dụng của Adapter Pattern:

  • Hệ thống cần sử dụng một class hiện có và Interface của class này không đáp ứng nhu cầu của hệ thống, nghĩa là Interface không tương thích;
  • Sử dụng service do bên thứ ba cung cấp, nhưng định nghĩa Interface của dịch vụ này lại khác với định nghĩa Interface của bạn.

Roundup

Như mọi khi, 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.

Cảm ơn và hẹn gặp lại các bạn trong những bài viết tiếp theo! 😍

Nếu bạn thấy Blog này hay xin hãy cho mình một like và đăng ký để ủng hộ mình nhé. Thank you.😉

Ref

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ