アプリケーションの複数の部分で共有する必要があるオブジェクト (データベース接続、WebSocket クライアント、構成マネージャーなど) を扱っていることに気付いたことがありますか?
アプリケーションやプロセスのライフサイクル全体を通じて一貫性を保ち、アクセスできるようにするには、このようなオブジェクトをどのように管理すればよいでしょうか?ここで シングルトン デザイン パターン が登場します。
シングルトン は 創造的なデザイン パターン であり、新しいオブジェクトを使用してオブジェクトを作成するネイティブな方法に伴うさまざまな問題に対処するデザイン パターンのカテゴリです。 キーワードまたは演算子。
シングルトン設計パターンは、次の 2 つの主要な問題を解決することに重点を置いています。
これにより、データベース接続、WebSocket クライアント、キャッシュ サービス、またはアプリケーションのライフサイクル全体を通じてメモリ内で永続化および変更する必要があるものなど、特定の種類またはタイプのグローバル状態を管理する方法が簡素化および標準化されます。
上記のスキーマは次の 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 は、インスタンス オブジェクトがクラスのインスタンスではなく、クラス定義自体に関連付けられていることを意味します。
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"
Singleton クラスに関連付けられた静的メソッド getInstance を呼び出すことで、上記のクラスを利用できます。
getInstance メソッドは、コードベースの異なる場所でクラスを複数回インスタンス化した場合でも、常に同じインスタンスを取得することを保証します。
したがって、両方の変数 (instance1 と instance2) は同じシングルトン インスタンスを共有します。
Prisma は、JavaScript エコシステムでよく知られた ORM です。アプリケーションで Prisma を使用するには、PrismaClient をインポートし、そこからオブジェクトをインスタンス化する必要があります。
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... }
Prisma クライアントは、遅延的な方法で、つまり、最初にエンティティのクエリまたは変更を試みたときにのみ、データベースに接続します。
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"
prismaClient がファイルにインポートされるたびに、PrismaClient から新しいインスタンスが作成されます。したがって、これらのインスタンスを使用するたびに、多くのデータベース接続が確立されます。
import { PrismaClient } from "@prisma/client" export const prismaClient = new PrismaClient()
データベースは通常、限られた数の接続しか処理できないため、多数のオープンデータベース接続はアプリケーションのパフォーマンスを低下させ、データベースのシャットダウンにつながる可能性もあります。
シングルトン デザイン パターン は、PrismaClient クラスのインスタンスが複数存在することを回避し、PrismaClientSingleton.getInstance() 静的メソッド経由でインスタンスにアクセスするための単一ポイントを提供することで、このような問題を防ぐのに役立ちます。
import { prismaClient } from "@/db" const users = await prismaClient.user.findMany() // query on the users table
これから説明するもう 1 つの実際的なシナリオは、メモリ内レート リミッター サービスです。
ユーザーやハッカーは、特定のエンドポイントに大量のリクエストを送信することで、そのエンドポイントにスパムを送信する可能性があります。これにより、脆弱性、予期せぬコスト、またはサーバー障害が発生する可能性があります。
これを防ぐために、基本的なインメモリ レート リミッター サービスを実装できます。
サービスは、特定のタイミング ウィンドウ間隔 (たとえば、60 秒) の間、IP アドレスごとのリクエストの数を制限する必要があります。
export const prismaClient = new PrismaClient() // a new instance is created every time it gets imported then used.
RateLimiterService クラスは、指定されたタイミング ウィンドウ内で IP アドレス (マップ キー) によって識別される特定のユーザーによって行われたリクエスト (requests[ip].count) の数を追跡するマップを保存します。 (リクエスト[ip].lastRequestTime).
私たちの RateLimiterService はグローバルに使用することを目的としています。つまり、RateLimiterService がインポートされるたびに、リクエスト マップ、リミット、ウィンドウ変数で構成される内部状態値をリセットする必要はありません。
シングルトン設計パターンは、アプリケーション内の共有リソースを効果的に管理するための強力なツールです
重要なポイント:
ご質問がある場合、またはさらに話し合いたい場合は、お気軽にここからご連絡ください。
コーディングを楽しんでください!
以上がシングルトン設計パターン: アプリケーションでのグローバル状態の管理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。