シングルトンとファクトリ パターン: 制御されたオブジェクトの作成
I クリエイティブなデザインパターン オブジェクト作成を柔軟に処理する そして再利用可能。 シングルトン クラスのインスタンスを 1 つだけ保証しますが、 工場 オブジェクトの作成を特殊なメソッドに委任します。どちらも 強固なソフトウェア アーキテクチャの基礎。
🎯 何を学ぶか
- シングルトン パターン: グローバル一意のインスタンス
- ファクトリ メソッド: 作成をサブクラスに委任する
- 抽象ファクトリー: 関連オブジェクトのファミリー
- 各パターンをいつ使用するか
シングルトンパターン
Il シングルトン クラスが持っていることを保証します 単一のインスタンス そして、そこへのグローバル アクセス ポイントを提供します。接続などの共有リソースに役立ちます データベース、ロガー、キャッシュ。
class DatabaseConnection {{ '{' }}
private static instance: DatabaseConnection;
private connected: boolean = false;
// Costruttore privato: impedisce `new DatabaseConnection()`
private constructor() {{ '{' }}
console.log("DatabaseConnection created");
{{ '}' }}
// Metodo statico per ottenere l'istanza unica
public static getInstance(): DatabaseConnection {{ '{' }}
if (!DatabaseConnection.instance) {{ '{' }}
DatabaseConnection.instance = new DatabaseConnection();
{{ '}' }}
return DatabaseConnection.instance;
{{ '}' }}
public connect(): void {{ '{' }}
if (!this.connected) {{ '{' }}
console.log("Connecting to database...");
this.connected = true;
{{ '}' }}
{{ '}' }}
public query(sql: string): void {{ '{' }}
console.log(`Executing: ${{ '{' }}sql{{ '}' }}`);
{{ '}' }}
{{ '}' }}
// Utilizzo
const db1 = DatabaseConnection.getInstance();
const db2 = DatabaseConnection.getInstance();
console.log(db1 === db2); // true - stessa istanza!
db1.connect();
db2.query("SELECT * FROM users"); // Usa la stessa connessione
遅延初期化を使用したシングルトン
インスタンスは、アプリケーションの起動時ではなく、必要な場合にのみ作成されます。
class Logger {{ '{' }}
private static instance: Logger;
private logs: string[] = [];
private constructor() {{ '{' }}{{ '}' }}
public static getInstance(): Logger {{ '{' }}
// Creato solo alla prima chiamata
if (!Logger.instance) {{ '{' }}
console.log("Logger instance created");
Logger.instance = new Logger();
{{ '}' }}
return Logger.instance;
{{ '}' }}
public log(message: string): void {{ '{' }}
const timestamp = new Date().toISOString();
this.logs.push(`[${{ '{' }}timestamp{{ '}' }}] ${{ '{' }}message{{ '}' }}`);
console.log(this.logs[this.logs.length - 1]);
{{ '}' }}
public getLogs(): string[] {{ '{' }}
return [...this.logs];
{{ '}' }}
{{ '}' }}
// Prima chiamata: crea istanza
const logger = Logger.getInstance(); // "Logger instance created"
logger.log("Application started");
// Chiamate successive: riutilizza istanza
const logger2 = Logger.getInstance(); // Nessun log di creazione
logger2.log("User logged in");
console.log(logger.getLogs());
// ["[2024-12-26T...] Application started", "[2024-12-26T...] User logged in"]
シングルトン: 長所と短所
✅ 利点:
- 単一インスタンスを保証します
- グローバルアクセス
- 遅延初期化
- 共有リソースの制御
❌ 短所:
- グローバルステータス (テストが困難)
- ヴィオラの単一責任
- 強い結合
- マルチスレッドの問題
⚠️ シングルトンの代替案
多くの場合、 依存関係の注入 シングルトンよりも好ましいです。 Angular のようなフレームワークは DI を使用して、シングルトン パターンの問題を発生させることなく単一のインスタンスを提供します。
ファクトリメソッドパターン
Il ファクトリーメソッド オブジェクトを作成するためのインターフェイスを定義しますが、デリゲートは サブクラスは、インスタンス化する具体的なクラスを決定します。
// Interfaccia prodotto
interface Vehicle {{ '{' }}
drive(): void;
getType(): string;
{{ '}' }}
// Prodotti concreti
class Car implements Vehicle {{ '{' }}
drive(): void {{ '{' }}
console.log("Driving a car 🚗");
{{ '}' }}
getType(): string {{ '{' }}
return "Car";
{{ '}' }}
{{ '}' }}
class Motorcycle implements Vehicle {{ '{' }}
drive(): void {{ '{' }}
console.log("Riding a motorcycle 🏍️");
{{ '}' }}
getType(): string {{ '{' }}
return "Motorcycle";
{{ '}' }}
{{ '}' }}
class Truck implements Vehicle {{ '{' }}
drive(): void {{ '{' }}
console.log("Driving a truck 🚚");
{{ '}' }}
getType(): string {{ '{' }}
return "Truck";
{{ '}' }}
{{ '}' }}
// Factory astratta
abstract class VehicleFactory {{ '{' }}
// Factory method (da implementare nelle sottoclassi)
abstract createVehicle(): Vehicle;
// Metodo che usa il factory method
public deliverVehicle(): void {{ '{' }}
const vehicle = this.createVehicle();
console.log(`Delivering a ${{ '{' }}vehicle.getType(){{ '}' }}`);
vehicle.drive();
{{ '}' }}
{{ '}' }}
// Factory concrete
class CarFactory extends VehicleFactory {{ '{' }}
createVehicle(): Vehicle {{ '{' }}
return new Car();
{{ '}' }}
{{ '}' }}
class MotorcycleFactory extends VehicleFactory {{ '{' }}
createVehicle(): Vehicle {{ '{' }}
return new Motorcycle();
{{ '}' }}
{{ '}' }}
class TruckFactory extends VehicleFactory {{ '{' }}
createVehicle(): Vehicle {{ '{' }}
return new Truck();
{{ '}' }}
{{ '}' }}
// Utilizzo
function clientCode(factory: VehicleFactory) {{ '{' }}
factory.deliverVehicle();
{{ '}' }}
clientCode(new CarFactory());
// "Delivering a Car"
// "Driving a car 🚗"
clientCode(new MotorcycleFactory());
// "Delivering a Motorcycle"
// "Riding a motorcycle 🏍️"
シンプルファクトリー(ファクトリーパターン)
より単純な変形: 単一のファクトリ メソッドでインスタンス化するクラスを決定します。
class VehicleSimpleFactory {{ '{' }}
public static createVehicle(type: string): Vehicle {{ '{' }}
switch (type) {{ '{' }}
case 'car':
return new Car();
case 'motorcycle':
return new Motorcycle();
case 'truck':
return new Truck();
default:
throw new Error(`Unknown vehicle type: ${{ '{' }}type{{ '}' }}`);
{{ '}' }}
{{ '}' }}
{{ '}' }}
// Utilizzo
const car = VehicleSimpleFactory.createVehicle('car');
car.drive(); // "Driving a car 🚗"
const truck = VehicleSimpleFactory.createVehicle('truck');
truck.drive(); // "Driving a truck 🚚"
抽象的な工場パターン
抽象的な工場 作成する 関連オブジェクトのファミリー なしで 具体的なクラスを指定します。 UI テーマ、マルチベンダー データベースなどに役立ちます。
// Interfacce prodotti
interface Button {{ '{' }}
render(): void;
{{ '}' }}
interface Checkbox {{ '{' }}
render(): void;
{{ '}' }}
// Prodotti concreti - Tema Dark
class DarkButton implements Button {{ '{' }}
render(): void {{ '{' }}
console.log("Rendering dark button");
{{ '}' }}
{{ '}' }}
class DarkCheckbox implements Checkbox {{ '{' }}
render(): void {{ '{' }}
console.log("Rendering dark checkbox");
{{ '}' }}
{{ '}' }}
// Prodotti concreti - Tema Light
class LightButton implements Button {{ '{' }}
render(): void {{ '{' }}
console.log("Rendering light button");
{{ '}' }}
{{ '}' }}
class LightCheckbox implements Checkbox {{ '{' }}
render(): void {{ '{' }}
console.log("Rendering light checkbox");
{{ '}' }}
{{ '}' }}
// Abstract Factory
interface UIFactory {{ '{' }}
createButton(): Button;
createCheckbox(): Checkbox;
{{ '}' }}
// Factory concrete
class DarkThemeFactory implements UIFactory {{ '{' }}
createButton(): Button {{ '{' }}
return new DarkButton();
{{ '}' }}
createCheckbox(): Checkbox {{ '{' }}
return new DarkCheckbox();
{{ '}' }}
{{ '}' }}
class LightThemeFactory implements UIFactory {{ '{' }}
createButton(): Button {{ '{' }}
return new LightButton();
{{ '}' }}
createCheckbox(): Checkbox {{ '{' }}
return new LightCheckbox();
{{ '}' }}
{{ '}' }}
// Client code
class Application {{ '{' }}
private button: Button;
private checkbox: Checkbox;
constructor(factory: UIFactory) {{ '{' }}
this.button = factory.createButton();
this.checkbox = factory.createCheckbox();
{{ '}' }}
render(): void {{ '{' }}
this.button.render();
this.checkbox.render();
{{ '}' }}
{{ '}' }}
// Utilizzo - Switch tema senza modificare Application
const darkApp = new Application(new DarkThemeFactory());
darkApp.render();
// "Rendering dark button"
// "Rendering dark checkbox"
const lightApp = new Application(new LightThemeFactory());
lightApp.render();
// "Rendering light button"
// "Rendering light checkbox"
各パターンをいつ使用するか
✅ 次の場合にシングルトンを使用します。
- 便利です 単一のインスタンス グローバル (ロガー、キャッシュ、構成)
- 共有リソースの制御(DB接続)
- より良い: 可能であれば、代わりに依存関係の注入を使用してください
✅ 次の場合にファクトリーメソッドを使用します。
- クラスは事前に知りません どのオブジェクトを作成するか
- 作成を委任しますか? サブクラス
- 拡張性が必要 (既存のコードを変更せずに新しいタイプを追加)
✅ 次の場合に Abstract Factory を使用します。
- 作成する必要があります 関連オブジェクトのファミリー
- オブジェクトは一緒に使用する必要があります (UI テーマ、クロスプラットフォーム UI)
- 実装の詳細を非表示にしたい
実践例:通知システム
// Singleton Logger
class NotificationLogger {{ '{' }}
private static instance: NotificationLogger;
private constructor() {{ '{' }}{{ '}' }}
static getInstance(): NotificationLogger {{ '{' }}
if (!this.instance) this.instance = new NotificationLogger();
return this.instance;
{{ '}' }}
log(msg: string): void {{ '{' }}
console.log(`[NOTIFICATION] ${{ '{' }}msg{{ '}' }}`);
{{ '}' }}
{{ '}' }}
// Factory per Notifiche
interface Notification {{ '{' }}
send(message: string): void;
{{ '}' }}
class EmailNotification implements Notification {{ '{' }}
send(message: string): void {{ '{' }}
NotificationLogger.getInstance().log(`Email sent: ${{ '{' }}message{{ '}' }}`);
{{ '}' }}
{{ '}' }}
class SMSNotification implements Notification {{ '{' }}
send(message: string): void {{ '{' }}
NotificationLogger.getInstance().log(`SMS sent: ${{ '{' }}message{{ '}' }}`);
{{ '}' }}
{{ '}' }}
class NotificationFactory {{ '{' }}
static create(type: 'email' | 'sms'): Notification {{ '{' }}
switch (type) {{ '{' }}
case 'email':
return new EmailNotification();
case 'sms':
return new SMSNotification();
{{ '}' }}
{{ '}' }}
{{ '}' }}
// Utilizzo
const emailNotif = NotificationFactory.create('email');
emailNotif.send("Welcome!"); // [NOTIFICATION] Email sent: Welcome!
const smsNotif = NotificationFactory.create('sms');
smsNotif.send("Code: 1234"); // [NOTIFICATION] SMS sent: Code: 1234
結論
シングルトンとファクトリーは基本的な作成パターンです。 シングルトン 保証する 単一のグローバル インスタンスですが、 工場 柔軟性を高めるためのデリゲートの作成。 抽象的な工場 オブジェクトのファミリーの概念を拡張します。慎重に使用してください。 多くの場合、依存関係の注入はシングルトンよりも推奨されますが、代わりにシンプル ファクトリで十分です。 複雑なファクトリーメソッド。
🎯 重要なポイント
- シングルトン = 1 つのグローバル インスタンス (プライベート コンストラクター)
- ファクトリ メソッド = サブクラスへの作成のデリゲート
- Simple Factory = 静的メソッドが何を作成するかを決定します
- 抽象ファクトリー = 関連オブジェクトのファミリー
- 可能な限りシングルトンよりも依存性注入を優先する







