0
0
Lập trình
Thaycacac
Thaycacac thaycacac

Mẫu thiết kế Singleton: Quản lý trạng thái toàn cục hiệu quả trong ứng dụng

Đăng vào 2 tháng trước

• 6 phút đọc

Chủ đề:

Development

Mẫu thiết kế Singleton: Quản lý trạng thái toàn cục hiệu quả trong ứng dụng

Bạn có bao giờ cần một đối tượng được chia sẻ và có thể truy cập từ nhiều phần khác nhau trong ứng dụng của bạn chưa? Đó có thể là kết nối tới cơ sở dữ liệu, WebSocket client hoặc dịch vụ quản lý cấu hình. Vậy làm thế nào để bạn có thể quản lý một đối tượng như vậy sao cho nó nhất quán và có thể truy cập qua toàn bộ vòng đời của ứng dụng? Đây chính là lúc mà Mẫu thiết kế Singleton trở thành giải pháp hữu hiệu.

Tổng quan về Mẫu thiết kế Singleton

Mẫu thiết kế Singleton là một kiểu mẫu thiết kế thuộc nhóm khởi tạo, giúp giải quyết các vấn đề liên quan đến việc tạo ra và quản lý các đối tượng. Nó có hai vấn đề chính cần giải quyết:

  • Cung cấp một điểm truy cập toàn cục cho instance của chúng ta là gì?
  • Làm thế nào để đảm bảo rằng một lớp chỉ có một instance duy nhất?

Singleton giúp chúng ta tiêu chuẩn hóa và đơn giản hóa việc quản lý trạng thái toàn cục trong ứng dụng, từ kết nối cơ sở dữ liệu cho đến WebSocket client hay dịch vụ caching.

Cách triển khai Mẫu thiết kế Singleton

Để triển khai mẫu thiết kế Singleton, chúng ta có thể sử dụng lớp TypeScript như sau:

typescript Copy
class Singleton {
  private static instance: Singleton;
  public authorName: string;

  private constructor({ authorName }: { authorName: string }) {
    this.authorName = authorName;
  }

  public static getInstance(params) {
    if (!this.instance) {
      this.instance = new Singleton(params);
    }
    return this.instance;
  }
}

Trong lớp này, chúng ta định nghĩa một thuộc tính tĩnh để lưu trữ instance duy nhất của lớp. Từ khóa static cho phép chúng ta lưu trữ sự kiện này không liên kết với các instance của lớp mà liên kết với chính định nghĩa lớp.
Constructor của lớp được đánh dấu là private, điều này có nghĩa rằng cách duy nhất để lấy một instance của lớp là thông qua phương thức tĩnh getInstance.

typescript Copy
const instance = Singleton.getInstance({ authorName: "Sidali Assoul" });

const instance1 = Singleton.getInstance({ authorName: "Sidali Assoul" }); // "Sidali Assoul"
const instance2 = Singleton.getInstance({ authorName: "John Doe" }); // "Sidali Assoul"

Thông qua phương thức getInstance, chúng ta có thể đảm bảo rằng mình luôn nhận được cùng một instance ngay cả khi khởi tạo lớp nhiều lần ở các phần khác nhau của mã lệnh.

Ứng dụng thực tế của Mẫu Singleton

Một số trường hợp tiêu biểu của mẫu thiết kế này bao gồm việc tối ưu hóa kết nối cơ sở dữ liệu qua Prisma - một ORM phổ biến của JavaScript. Để sử dụng Prisma trong ứng dụng, chúng ta sẽ làm như sau:

typescript Copy
import { PrismaClient } from "@prisma/client";

export const prismaClient = new PrismaClient();

Prisma client sẽ kết nối với cơ sở dữ liệu một cách lười biếng, nghĩa là chỉ khi truy vấn hoặc thay đổi thực thể lần đầu.

Mỗi khi prismaClient được import trong một file, một instance mới sẽ được tạo ra. Điều này có thể dẫn đến hàng loạt kết nối cơ sở dữ liệu không mong muốn:

typescript Copy
export const prismaClient = new PrismaClient(); // một instance mới được tạo ra mỗi lần import

Việc mở nhiều kết nối cơ sở dữ liệu như vậy sẽ giảm hiệu suất ứng dụng và có thể khiến cơ sở dữ liệu bị tắc nghẽn. Mẫu Singleton giúp ngăn chặn điều này bằng cách giới hạn số lượng instance của lớp PrismaClient và cung cấp một cách tiếp cận toàn cục thông qua phương thức PrismaClientSingleton.getInstance().

typescript Copy
import { PrismaClient } from "@prisma/client";

class PrismaClientSingleton {
  private static instance: PrismaClient;

  private constructor() {}

  public static getInstance(): PrismaClient {
    if (!PrismaClientSingleton.instance) {
      PrismaClientSingleton.instance = new PrismaClient();
    }
    return PrismaClientSingleton.instance;
  }
}

export default PrismaClientSingleton;

Kịch bản thực hành thứ hai: Dịch vụ Hạn chế Tốc độ

Một ví dụ thực tế khác về mẫu Singleton là dịch vụ hạn chế tốc độ trong bộ nhớ (in-memory rate limiter). Với một dịch vụ này, chúng ta có thể ngăn chặn việc spam request đến một endpoint cụ thể, giúp bảo vệ ứng dụng khỏi các lỗ hổng bảo mật và giảm thiểu chi phí không cần thiết. Dịch vụ này sẽ giới hạn số lượng request mà mỗi địa chỉ IP có thể gửi trong khoảng thời gian nhất định (chẳng hạn như 60 giây).

typescript Copy
class RateLimiterService {
  private static instance: RateLimiterService;
  private requests: Map<string, { count: number; lastRequestTime: number }>; 
  private readonly limit: number; // Số lượng request tối đa
  private readonly window: number; // Khoảng thời gian tính bằng milli giây

  private constructor(limit: number = 5, window: number = 60000) {
    this.requests = new Map();
    this.limit = limit;
    this.window = window;
  }

  public static getInstance(): RateLimiterService {
    if (!RateLimiterService.instance) {
      RateLimiterService.instance = new RateLimiterService();
    }
    return RateLimiterService.instance;
  }

  public isRateLimited(ip: string): boolean {
    const currentTime = Date.now();
    const userRequestData = this.requests.get(ip);

    if (userRequestData) {
      const isExpired = currentTime - userRequestData.lastRequestTime > this.window;

      if (isExpired) {
        userRequestData.count = 1;
        userRequestData.lastRequestTime = currentTime;
        return false;
      } else {
        userRequestData.count++;
        if (userRequestData.count > this.limit) {
          return true;
        }
        return false;
      }
    } else {
      this.requests.set(ip, { count: 1, lastRequestTime: currentTime });
      return false;
    }
  }
}

export default RateLimiterService;

Lớp RateLimiterService theo dõi số lượng request của mỗi địa chỉ IP, điều này giúp chúng ta sở hữu trạng thái toàn cục và không cần phải khởi tạo lại các giá trị mỗi khi RateLimiterService được sử dụng.

Kết luận

Mẫu thiết kế Singleton là một công cụ mạnh mẽ giúp quản lý hiệu quả tài nguyên trong ứng dụng của chúng ta. Đây là những điểm quan trọng cần nhớ:

  • Singleton đảm bảo rằng một lớp chỉ có một instance và cung cấp điểm truy cập toàn cục cho nó.
  • Rất hữu ích trong việc quản lý tài nguyên được chia sẻ như kết nối cơ sở dữ liệu và cài đặt cấu hình.
  • Ứng dụng thực tế bao gồm việc tối ưu hóa kết nối cơ sở dữ liệu với ORM như Prisma và triển khai các dịch vụ hạn chế tốc độ.
    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