工厂模式结合单例:从内存选取对象是否符合模式规范?
Great question! Let's break this down clearly—first addressing whether this fits the Factory Pattern, then covering patterns that will solve your decoupling goal perfectly.
Does this fit the Factory Pattern?
Short answer: No, not strictly.
The core intent of all Factory Pattern variants (Simple Factory, Factory Method, Abstract Factory) is to create new objects while abstracting the instantiation logic from the caller. Your scenario is the opposite: you're selecting from a pre-loaded pool of existing objects in memory, not constructing new ones.
That said, you are borrowing a key factory principle: encapsulating the logic of how you retrieve an object so the caller doesn't need to know the details. But since object creation isn't involved, it doesn't align with the formal definition of the Factory Pattern.
Patterns to Decouple Requests from Concrete Objects
Here are two perfect fits for your use case, along with a quick implementation example:
1. Service Locator Pattern
Think of your Items Manager as a centralized service locator that stores objects grouped by type, and exposes a clean API to fetch random items by their type string. The caller only interacts with this locator interface, never the underlying storage or selection logic.
2. Repository Pattern
While often associated with persistent data, the Repository Pattern works equally well for in-memory object collections. It acts as a "data access layer" for your pre-loaded objects, encapsulating queries (like filtering by type and picking a random entry) behind a simple interface. This decouples the caller from how objects are stored or retrieved.
Example Implementation (TypeScript)
Here's how you might build an Items Manager using a Service Locator approach:
class ItemsManager { private itemPool: Map<string, Array<Animal>> = new Map(); // Load pre-created objects into the manager during app startup initialize(items: Animal[]): void { items.forEach(item => { const type = item.getAnimalType(); // Assume each object has a method to get its type if (!this.itemPool.has(type)) { this.itemPool.set(type, []); } this.itemPool.get(type)!.push(item); }); } // Fetch a random item by type string getRandomItemByType(type: string): Animal | undefined { const items = this.itemPool.get(type); if (!items || items.length === 0) { return undefined; } const randomIndex = Math.floor(Math.random() * items.length); return items[randomIndex]; } } // Usage in your app const animalManager = new ItemsManager(); animalManager.initialize([new Sparrow(), new Eagle(), new Wolf()]); const randomBird = animalManager.getRandomItemByType("bird");
This setup keeps your caller code clean and decoupled: it only needs to know the type string and the getRandomItemByType method, not how objects are stored, grouped, or selected.
Bonus: Object Pool Pattern
Honorable mention: if your pre-loaded objects are meant to be reused (instead of just fetched once), the Object Pool Pattern aligns closely. It manages a pool of ready-to-use objects, and you can extend it to include type-based retrieval—though for your specific decoupling need, Service Locator or Repository is more direct.
内容的提问来源于stack exchange,提问作者user9767538

