import 'reflect-metadata'; import { DI, Injectable, Inject, Scope } from '../src/common'; // ===== INTERFACES ===== interface ILogger { log(message: string): void; } interface ICache { get(key: string): any; set(key: string, value: any): void; } interface IDatabase { connect(): void; disconnect(): void; query(sql: string): any[]; } interface IConfig { database: { host: string; port: number; name: string; }; cache: { ttl: number; }; } // ===== IMPLEMENTATIONS ===== @Injectable() class Logger implements ILogger { log(message: string): void { console.log(`[LOG] ${new Date().toISOString()}: ${message}`); } } @Injectable() class Cache implements ICache { private data = new Map(); get(key: string): any { return this.data.get(key); } set(key: string, value: any): void { this.data.set(key, value); } } @Injectable() class Database implements IDatabase { constructor( private config: IConfig, private logger: ILogger, private cache: ICache ) {} connect(): void { this.logger.log(`Connecting to database: ${this.config.database.host}:${this.config.database.port}/${this.config.database.name}`); } disconnect(): void { this.logger.log('Disconnecting from database'); } query(sql: string): any[] { this.logger.log(`Executing query: ${sql}`); return [{ id: 1, name: 'test' }]; } } // ===== FACTORY FUNCTIONS ===== // 1. Traditional factory (only dependencies as arguments) function createDatabaseTraditional(config: IConfig): IDatabase { // Problem: No access to DI container, must create dependencies manually const logger = new Logger(); const cache = new Cache(); return new Database(config, logger, cache); } // 2. Factory with DI container access function createDatabaseWithDI(container: any, config: IConfig): IDatabase { // Solution: Access to DI container, can get other dependencies const logger = container.get('ILogger') as ILogger; const cache = container.get('ICache') as ICache; return new Database(config, logger, cache); } // 3. Factory with DI container access and additional dependencies function createDatabaseAdvanced(container: any, config: IConfig, customLogger?: ILogger): IDatabase { // Can use DI container AND additional dependencies const logger = customLogger || container.get('ILogger') as ILogger; const cache = container.get('ICache') as ICache; // Can even create new instances dynamically const db = new Database(config, logger, cache); // Can register additional services if needed container.bind('CustomDatabase').toValue(db); return db; } // ===== CONFIGURATION ===== const appConfig: IConfig = { database: { host: 'localhost', port: 5432, name: 'myapp' }, cache: { ttl: 3600 } }; // ===== REGISTRATION ===== async function setupDI() { console.log('🚀 Setting up DI with factory examples...\n'); // Register basic services DI.bind('ILogger').toClass(Logger); DI.bind('ICache').toClass(Cache); DI.bind('AppConfig').toValue(appConfig); // 1. Traditional factory (no container access) DI.bind('DatabaseTraditional').toFactory(createDatabaseTraditional, { dependencies: ['AppConfig'] }); // 2. Factory with DI container access DI.bind('DatabaseWithDI').toFactory(createDatabaseWithDI, { dependencies: ['AppConfig'], injectContainer: true // This enables container injection }); // 3. Factory with DI container access and additional dependencies DI.bind('DatabaseAdvanced').toFactory(createDatabaseAdvanced, { dependencies: ['AppConfig'], injectContainer: true }); console.log('✅ All dependencies registered!\n'); } // ===== USAGE ===== async function demonstrateUsage() { console.log('📋 Demonstrating factory usage...\n'); // 1. Traditional factory console.log('1️⃣ Traditional Factory (no DI access):'); const dbTraditional = DI.get('DatabaseTraditional'); dbTraditional.connect(); dbTraditional.query('SELECT * FROM users'); dbTraditional.disconnect(); console.log(''); // 2. Factory with DI access console.log('2️⃣ Factory with DI Container Access:'); const dbWithDI = DI.get('DatabaseWithDI'); dbWithDI.connect(); dbWithDI.query('SELECT * FROM users'); dbWithDI.disconnect(); console.log(''); // 3. Advanced factory console.log('3️⃣ Advanced Factory with DI Container Access:'); const dbAdvanced = DI.get('DatabaseAdvanced'); dbAdvanced.connect(); dbAdvanced.query('SELECT * FROM users'); dbAdvanced.disconnect(); console.log(''); // Show that custom database was registered console.log('🔍 Checking if custom database was registered:'); if (DI.has('CustomDatabase')) { const customDb = DI.get('CustomDatabase'); console.log('✅ Custom database was registered by factory!'); customDb.query('SELECT * FROM custom_table'); } console.log(''); // Show all registered tokens console.log('📊 All registered tokens:'); console.log(DI.getTokens()); } // ===== MAIN ===== async function main() { try { await setupDI(); await demonstrateUsage(); console.log('🎉 Factory with DI container example completed successfully!'); } catch (error) { console.error('❌ Error:', error); } } // Run the example main();