برنامه نویسی

الگوی طراحی Singleton: مدیریت کشورهای جهانی در برنامه های کاربردی شما

Summarize this content to 400 words in Persian Lang
آیا تا به حال متوجه شده اید که با یک شی سروکار دارید که باید در چندین بخش برنامه شما به اشتراک گذاشته شود – شاید یک اتصال پایگاه داده، یک سرویس گیرنده WebSocket یا یک مدیر پیکربندی؟

چگونه چنین شی ای را مدیریت می کنید تا در طول چرخه عمر برنامه یا فرآیند سازگار و قابل دسترسی باقی بماند؟ اینجاست که الگوی طراحی Singleton وارد بازی می شود.

نمای کلی

سینگلتون یک است الگوی طراحی خلاقانه ، که دسته ای از الگوهای طراحی است که به مشکلات مختلفی می پردازد که با روش بومی ایجاد اشیا با جدید کلمه کلیدی یا عملگر

را الگوی طراحی Singleton بر حل دو مشکل اصلی تمرکز دارد:

چگونه می توانیم a نقطه دسترسی جهانی به مثال ما؟
چگونه می توانیم اطمینان حاصل کنیم که الف کلاس یا نوع خاصی از اشیاء فقط یک نمونه دارد؟

این می تواند نحوه مدیریت نوع یا نوع خاصی از حالت جهانی مانند اتصالات پایگاه داده، سرویس گیرندگان WebSocket، سرویس های کش یا هر چیزی را که نیاز داریم در طول چرخه عمر برنامه در حافظه باقی بماند و تغییر کند، ساده و استاندارد کند.

چگونه می توانیم الگوی طراحی Singleton را پیاده سازی کنیم؟

طرحواره بالا به این کلاس TypeScript ترجمه می شود:

نمونه TypeScript

class Singleton {
private static instance: Singleton
// other properties…
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
}
// other methods…
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کلاس باید یک ویژگی ثابت برای ذخیره نمونه قابل اشتراک گذاری منحصر به فرد تعریف کند.

کلمه کلیدی static به این معنی است که شی نمونه با نمونه های کلاس مرتبط نیست بلکه با خود تعریف کلاس مرتبط است.

سازنده کلاس باید به عنوان خصوصی علامت گذاری شود. تنها راه برای به دست آوردن نمونه ای از کلاس ما، تماس با آن است getInstance روش استاتیک

const instance = Singleton.getInstance({ authorName: “Sidali Assoul” })

// let’s imagine
const instance1 = Singleton.getInstance({ authorName: “Sidali Assoul” }) // “Sidali Assoul”
const instance2 = Singleton.getInstance({ authorName: “John Doe” }) // “Sidali Assoul”

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با فراخوانی متد static می توانیم از کلاس فوق استفاده کنیم getInstance که با کلاس Singleton مرتبط است.

را getInstance متد به ما تضمین می‌کند که همیشه همان نمونه را دریافت می‌کنیم، حتی اگر کلاس خود را چندین بار در مکان‌های مختلف پایگاه کد خود نمونه‌سازی کنیم.

بنابراین هر دو متغیر (instance1 و instance2) همان نمونه تکی را به اشتراک بگذارید.

اولین سناریوی عملی

پریسما یک ORM شناخته شده در اکوسیستم جاوا اسکریپت است. برای استفاده از Prisma در برنامه خود، باید a را وارد کنید PrismaClient سپس یک شی را از آن نمونه سازی کنید.

import { PrismaClient } from “@prisma/client”

export const prismaClient = new PrismaClient()

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را مشتری پریسما به شیوه ای تنبل یا به عبارت دیگر، تنها زمانی به پایگاه داده متصل می شود که برای اولین بار سعی می کنید یک موجودیت را پرس و جو کنید یا جهش دهید.

import { prismaClient } from “@/db”

const users = await prismaClient.user.findMany() // query on the users table

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر بار که prismaClient در یک فایل وارد می شود، یک نمونه جدید از آن ساخته می شود PrismaClient. از این رو، هر بار که از آن نمونه ها استفاده می کنیم، بسیاری از اتصالات پایگاه داده برقرار می شوند.

export const prismaClient = new PrismaClient() // a new instance is created every time it gets imported then used.

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بسیاری از اتصالات پایگاه داده باز عملکرد برنامه شما را کاهش می دهند و حتی ممکن است منجر به خاموش شدن پایگاه داده شوند زیرا پایگاه داده ها معمولاً فقط می توانند تعداد محدودی از اتصالات را مدیریت کنند.

را الگوی طراحی Singleton می تواند به ما کمک کند با اجتناب از داشتن بیش از یک نمونه از چنین موضوعی جلوگیری کنیم PrismaClient کلاس و با ارائه یک نقطه واحد برای دسترسی به آن از طریق PrismaClientSingleton.getInstance() روش استاتیک

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

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سناریوی عملی دوم

سناریوی عملی دیگری که ما از آن عبور خواهیم کرد، یک سناریوی است سرویس محدود کننده نرخ درون حافظه.

کاربران یا هکرها می‌توانند یک نقطه پایانی خاص را با درخواست‌های فراوان به آن اسپم کنند. این می تواند منجر به آسیب پذیری ها، هزینه های غیرمنتظره یا خرابی سرور شود.

برای جلوگیری از آن، می‌توانیم یک سرویس محدودکننده نرخ درون حافظه را پیاده‌سازی کنیم.

این سرویس باید تعداد درخواست‌ها را محدود کند IP آدرس برای یک بازه زمانی خاص (مثلاً 60 ثانیه).

class RateLimiterService {
private static instance: RateLimiterService
private requests: Map
private readonly limit: number // Maximum number of requests
private readonly window: number // Time window in milliseconds

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

// Method to get a unique singleton instance
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

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را RateLimiterService کلاس نقشه ای را ذخیره می کند که تعداد درخواست ها را ردیابی می کند (requests[ip].count) ساخته شدن توسط یک کاربر خاص که توسط یک شناسایی شده است آدرس IP (کلید نقشه) در یک پنجره زمان بندی داده شده (requests[ip].lastRequestTime).

ما RateLimiterService قرار است به صورت جهانی مورد استفاده قرار گیرد، یا به عبارت دیگر، ما نمی خواهیم مقادیر حالت داخلی متشکل از requests نقشه، limit، و window متغیرها هر بار RateLimiterService وارد می شود

نتیجه گیری

را الگوی طراحی Singleton یک ابزار قدرتمند برای مدیریت موثر منابع مشترک در برنامه های ما است

خوراکی های کلیدی:

Singleton تضمین می کند که یک کلاس فقط یک نمونه دارد و یک نقطه دسترسی جهانی به آن فراهم می کند.
برای مدیریت منابع مشترک مانند اتصالات پایگاه داده، تنظیمات پیکربندی یا حافظه پنهان مفید است.
کاربردهای عملی شامل بهینه سازی ارتباطات پایگاه داده با ORMهایی مانند Prisma و پیاده سازی خدمات محدود کننده نرخ است.

تماس بگیرید

اگر سوالی دارید یا می خواهید در مورد چیزی بیشتر بحث کنید، با من در اینجا تماس بگیرید.

کد نویسی مبارک!

آیا تا به حال متوجه شده اید که با یک شی سروکار دارید که باید در چندین بخش برنامه شما به اشتراک گذاشته شود – شاید یک اتصال پایگاه داده، یک سرویس گیرنده WebSocket یا یک مدیر پیکربندی؟

چگونه چنین شی ای را مدیریت می کنید تا در طول چرخه عمر برنامه یا فرآیند سازگار و قابل دسترسی باقی بماند؟ اینجاست که الگوی طراحی Singleton وارد بازی می شود.

نمای کلی

سینگلتون یک است الگوی طراحی خلاقانه ، که دسته ای از الگوهای طراحی است که به مشکلات مختلفی می پردازد که با روش بومی ایجاد اشیا با جدید کلمه کلیدی یا عملگر

را الگوی طراحی Singleton بر حل دو مشکل اصلی تمرکز دارد:

  1. چگونه می توانیم a نقطه دسترسی جهانی به مثال ما؟
  2. چگونه می توانیم اطمینان حاصل کنیم که الف کلاس یا نوع خاصی از اشیاء فقط یک نمونه دارد؟

این می تواند نحوه مدیریت نوع یا نوع خاصی از حالت جهانی مانند اتصالات پایگاه داده، سرویس گیرندگان WebSocket، سرویس های کش یا هر چیزی را که نیاز داریم در طول چرخه عمر برنامه در حافظه باقی بماند و تغییر کند، ساده و استاندارد کند.

چگونه می توانیم الگوی طراحی Singleton را پیاده سازی کنیم؟

طرح الگوی طراحی Singleton

طرحواره بالا به این کلاس TypeScript ترجمه می شود:

نمونه TypeScript

class Singleton {
  private static instance: Singleton
  // other properties...
  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
  }
  // other methods...
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • کلاس باید یک ویژگی ثابت برای ذخیره نمونه قابل اشتراک گذاری منحصر به فرد تعریف کند.

کلمه کلیدی static به این معنی است که شی نمونه با نمونه های کلاس مرتبط نیست بلکه با خود تعریف کلاس مرتبط است.

  • سازنده کلاس باید به عنوان خصوصی علامت گذاری شود. تنها راه برای به دست آوردن نمونه ای از کلاس ما، تماس با آن است getInstance روش استاتیک
const instance = Singleton.getInstance({ authorName: "Sidali Assoul" })


// let's imagine
const instance1 = Singleton.getInstance({ authorName: "Sidali Assoul" }) // "Sidali Assoul"
const instance2 = Singleton.getInstance({ authorName: "John Doe" }) // "Sidali Assoul"

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با فراخوانی متد static می توانیم از کلاس فوق استفاده کنیم getInstance که با کلاس Singleton مرتبط است.

را getInstance متد به ما تضمین می‌کند که همیشه همان نمونه را دریافت می‌کنیم، حتی اگر کلاس خود را چندین بار در مکان‌های مختلف پایگاه کد خود نمونه‌سازی کنیم.

دو متغیر که به یک Singleton اشاره می کنند

بنابراین هر دو متغیر (instance1 و instance2) همان نمونه تکی را به اشتراک بگذارید.

اولین سناریوی عملی

پریسما یک ORM شناخته شده در اکوسیستم جاوا اسکریپت است. برای استفاده از Prisma در برنامه خود، باید a را وارد کنید PrismaClient سپس یک شی را از آن نمونه سازی کنید.

import { PrismaClient } from "@prisma/client"

export const prismaClient = new PrismaClient()

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را مشتری پریسما به شیوه ای تنبل یا به عبارت دیگر، تنها زمانی به پایگاه داده متصل می شود که برای اولین بار سعی می کنید یک موجودیت را پرس و جو کنید یا جهش دهید.

import { prismaClient } from "@/db"

const users = await prismaClient.user.findMany() // query on the users table

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر بار که prismaClient در یک فایل وارد می شود، یک نمونه جدید از آن ساخته می شود PrismaClient. از این رو، هر بار که از آن نمونه ها استفاده می کنیم، بسیاری از اتصالات پایگاه داده برقرار می شوند.

export const prismaClient = new PrismaClient() // a new instance is created every time it gets imported then used.

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بسیاری از اتصالات پایگاه داده باز عملکرد برنامه شما را کاهش می دهند و حتی ممکن است منجر به خاموش شدن پایگاه داده شوند زیرا پایگاه داده ها معمولاً فقط می توانند تعداد محدودی از اتصالات را مدیریت کنند.

را الگوی طراحی Singleton می تواند به ما کمک کند با اجتناب از داشتن بیش از یک نمونه از چنین موضوعی جلوگیری کنیم PrismaClient کلاس و با ارائه یک نقطه واحد برای دسترسی به آن از طریق PrismaClientSingleton.getInstance() روش استاتیک

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

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سناریوی عملی دوم

سناریوی عملی دیگری که ما از آن عبور خواهیم کرد، یک سناریوی است سرویس محدود کننده نرخ درون حافظه.

کاربران یا هکرها می‌توانند یک نقطه پایانی خاص را با درخواست‌های فراوان به آن اسپم کنند. این می تواند منجر به آسیب پذیری ها، هزینه های غیرمنتظره یا خرابی سرور شود.

برای جلوگیری از آن، می‌توانیم یک سرویس محدودکننده نرخ درون حافظه را پیاده‌سازی کنیم.

این سرویس باید تعداد درخواست‌ها را محدود کند IP آدرس برای یک بازه زمانی خاص (مثلاً 60 ثانیه).

class RateLimiterService {
  private static instance: RateLimiterService
  private requests: Map
  private readonly limit: number // Maximum number of requests
  private readonly window: number // Time window in milliseconds

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

  // Method to get a unique singleton instance
  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

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را RateLimiterService کلاس نقشه ای را ذخیره می کند که تعداد درخواست ها را ردیابی می کند (requests[ip].count) ساخته شدن توسط یک کاربر خاص که توسط یک شناسایی شده است آدرس IP (کلید نقشه) در یک پنجره زمان بندی داده شده (requests[ip].lastRequestTime).

ما RateLimiterService قرار است به صورت جهانی مورد استفاده قرار گیرد، یا به عبارت دیگر، ما نمی خواهیم مقادیر حالت داخلی متشکل از requests نقشه، limit، و window متغیرها هر بار RateLimiterService وارد می شود

نتیجه گیری

را الگوی طراحی Singleton یک ابزار قدرتمند برای مدیریت موثر منابع مشترک در برنامه های ما است

خوراکی های کلیدی:

  1. Singleton تضمین می کند که یک کلاس فقط یک نمونه دارد و یک نقطه دسترسی جهانی به آن فراهم می کند.
  2. برای مدیریت منابع مشترک مانند اتصالات پایگاه داده، تنظیمات پیکربندی یا حافظه پنهان مفید است.
  3. کاربردهای عملی شامل بهینه سازی ارتباطات پایگاه داده با ORMهایی مانند Prisma و پیاده سازی خدمات محدود کننده نرخ است.

تماس بگیرید

اگر سوالی دارید یا می خواهید در مورد چیزی بیشتر بحث کنید، با من در اینجا تماس بگیرید.

کد نویسی مبارک!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا