singleton_manager 0.3.1
singleton_manager: ^0.3.1 copied to clipboard
A high-performance singleton manager for Dart with zero dependencies, type-safe generics support, lazy loading, and optional scope management. Ideal for dependency injection, service locators, and res [...]
example/README.md
Singleton Manager Examples #
Comprehensive examples demonstrating all features of the singleton_manager package.
Overview #
This directory contains 11 progressively advanced examples showing how to use singleton_manager in different scenarios:
1. Basic Singleton Manager (1_basic_singleton_manager.dart) #
What it covers:
- Simple Type-based singleton registration
- Using
SingletonManagerfor basic patterns - Register, retrieve, unregister, and clear operations
- Verifying singleton behavior (same instance)
Key concepts:
SingletonManager.instance- static singleton accessorregister<T>(value)- register by TypegetInstance<T>()- retrieve by Typeunregister<T>()- remove by Type
When to use:
- Simple applications with just a few singletons
- When you don't need key-value pairs or lazy loading
- Type-safe singleton pattern
2. Registry: Eager and Lazy Loading (2_registry_eager_and_lazy.dart) #
What it covers:
- Key-value registry pattern with String keys
- Eager registration (create immediately)
- Lazy registration (create on first access)
- Service replacement with version tracking
- Registry queries (keys, size, contains)
Key concepts:
Registry<Key, Value>mixin - flexible key-value registryregister(key, value)- eager registrationregisterLazy(key, factory)- deferred initializationreplace(key, value)/replaceLazy(key, factory)- update existinggetInstance(key)- transparent lazy resolutiondestroyAll()- cleanup with destroy() calls
When to use:
- When you need string-based or enum-based keys
- For lazy loading of expensive resources
- Complex applications with many related services
- Hot-reload/hot-swap scenarios
3. Dependency Injection (3_dependency_injection.dart) #
What it covers:
- Type-keyed DI container
- Interface-based service registration
- Constructor/method injection
- Service composition
- Async service usage
Key concepts:
- Type as registry key for interfaces/implementations
- Manual dependency injection
- Container pattern
- Proper cleanup with
destroyAll()
When to use:
- Medium to large applications
- Services with multiple dependencies
- Test-friendly architecture
- Replacing implementations easily
4. Error Handling (4_error_handling.dart) #
What it covers:
DuplicateRegistrationError- prevent silent overwritesRegistryNotFoundError- safe access patterns- Error handling with try-catch
- Safe pre-access checks with
contains() - Recovery from errors
Key concepts:
- Custom error types for clarity
- Using
replace()for updates (not register again) - Checking before accessing:
contains(key) - Lazy factory errors vs entry errors
When to use:
- Production-safe code
- Preventing bugs from duplicate registrations
- Robust error handling
- Defensive programming
5. Async Initialization (5_async_initialization.dart) #
What it covers:
ISingleton<InitializeType, ReturnType>interface- Async initialization with
initializeDI() - Custom initialization with
initialize(input) - Services that need async setup (DB, files, APIs)
- Proper async/await patterns
Key concepts:
ISingletoninterface for async initialization- Two-phase initialization:
initialize()andinitializeDI() - Async resource setup
- Lifecycle management
When to use:
- Services requiring async initialization
- Database connections, file I/O, API calls
- Configuration loading
- Complex startup sequences
6. Version Tracking and Replacement (6_version_tracking_and_replace.dart) #
What it covers:
- Version numbers for registered services
- Hot-reloading/hot-swapping services
- Tracking configuration changes
- Multiple replacements
- Mixed eager/lazy replacement
Key concepts:
ValueWithVersion<RegistryEntry<Value>>internal structure- Version increments on replace
getByKey()for version access- Old instance destruction on replace
When to use:
- Hot-reload scenarios
- Configuration updates at runtime
- A/B testing different implementations
- Dynamic service replacement
7. Complex Real-World Scenario (7_complex_real_world_scenario.dart) #
What it covers:
- Multi-layer architecture (Data, Business, Presentation)
- Repository pattern
- Service composition
- Dependency graph
- Full application lifecycle
Key concepts:
- Data layer (Database, Repository)
- Business logic layer (Services)
- Presentation layer (Controllers)
- Dependency chain setup
- Proper initialization order
When to use:
- Real-world applications
- Learning best practices
- Understanding proper layering
- Complex dependency structures
8. SingletonDI Factory Pattern (8_singleton_di_factory_pattern.dart) #
What it covers:
SingletonDIglobal factory registry- Registering factory functions
- Lazy singleton creation from factories
- Type-based factory lookup
getFactory<T>()andclearFactories()
Key concepts:
SingletonDI.registerFactory<T>(factory)- global registrySingletonDI.getFactory<T>()- retrieve factorySingletonDI.clearFactories()- cleanupSingletonDI.factoryCount- count registered
When to use:
- Large applications with many singletons
- Centralized factory configuration
- Delayed or complex singleton creation
- Plugin systems
9. Testing and Mocking (9_testing_and_mocking.dart) #
What it covers:
- Mock implementations of services
- Replacing real services with mocks
- Testing with controlled dependencies
- Verification of mock calls
- Mixed production/mock setup
- Test cleanup
Key concepts:
- Mock implementations
replace()for swapping implementations- Verification patterns
- Test registry setup/teardown
When to use:
- Writing unit tests
- Mocking expensive operations (DB, network)
- Testing in isolation
- Integration tests with mixed components
10. Performance and Best Practices (10_performance_and_best_practices.dart) #
What it covers:
- Lazy loading for expensive resources
- Resource pooling patterns
- Eager loading for critical services
- Batch operations
- Proper cleanup
- Error-safe operations
- Performance measurement
Key concepts:
- When to use lazy vs eager
- Resource pooling for connections
- Lifecycle management
- Batch registration
- Safe error handling
When to use:
- Learning best practices
- Optimizing application startup
- Resource management
- Performance-critical code
11. SingletonDIAccess - Static Methods and Instance-Based Registration (v0.3.0+) (11_singleton_di_access_static_methods.dart) #
What it covers:
SingletonDIAccessstatic convenience methods- Instance-based registration with
addInstance<T>() - Interface-based instance registration with
addInstanceAs<I, T>() - Comparison with factory-based registration
- Pre-configured objects for testing
- Simplified API without explicit instance management
Key concepts:
SingletonDIAccess.add<T>()- Static factory registrationSingletonDIAccess.addInstance<T>(instance)- Static instance registrationSingletonDIAccess.addInstanceAs<I, T>(instance)- Static interface-based instance registrationSingletonDIAccess.get<T>()- Static retrievalSingletonDIAccess.remove<T>()- Static removal- Benefits of static access and instance-based patterns
When to use:
- Simplified code without manager instance access
- Pre-configured services for testing
- Complex object setup before registration
- Utility functions and test helpers
- When you need cleaner, more concise code
Running the Examples #
Option 1: Run individual examples #
cd packages/singleton_manager
dart run example/1_basic_singleton_manager.dart
dart run example/2_registry_eager_and_lazy.dart
# ... etc
Option 2: Run all examples #
cd packages/singleton_manager
dart run example/1_basic_singleton_manager.dart && \
dart run example/2_registry_eager_and_lazy.dart && \
dart run example/3_dependency_injection.dart && \
# ... continue with others
Option 3: Using pub #
cd packages/singleton_manager
flutter pub get # or: dart pub get
dart run example/1_basic_singleton_manager.dart
Learning Path #
Beginner #
- Start with
1_basic_singleton_manager.dart- understand basics - Move to
3_dependency_injection.dart- see practical usage - Review
4_error_handling.dart- write safe code
Intermediate #
- Study
2_registry_eager_and_lazy.dart- understand all registry features - Learn
6_version_tracking_and_replace.dart- hot-reload patterns - Practice with
9_testing_and_mocking.dart- test-friendly code
Advanced #
- Explore
7_complex_real_world_scenario.dart- architectural patterns - Master
8_singleton_di_factory_pattern.dart- advanced patterns - Optimize with
10_performance_and_best_practices.dart- production-ready - Deep dive
5_async_initialization.dart- complex async patterns - Learn
11_singleton_di_access_static_methods.dart- v0.3.0+ features (static API and instance-based registration)
Common Patterns #
Pattern: Service Locator #
final manager = SingletonManager.instance;
manager.register<UserService>(UserService());
final service = manager.getInstance<UserService>();
Pattern: DI Container #
class AppContainer with Registry<Type, Object> {
void setup() {
register(IRepository, Repository());
register(IService, Service());
}
}
Pattern: Factory Registry #
SingletonDI.registerFactory<Service>(() => Service());
final service = SingletonDI.getFactory<Service>()!();
Pattern: Static DI Access (v0.3.0+) #
SingletonDI.registerFactory<Service>(() => Service());
await SingletonDIAccess.add<Service>();
final service = SingletonDIAccess.get<Service>();
Pattern: Instance-Based Registration (v0.3.0+) #
final service = Service(); // Pre-configured
await SingletonDIAccess.addInstance<Service>(service);
final retrieved = SingletonDIAccess.get<Service>();
Pattern: Lazy Loading #
registry.registerLazy('expensive', () {
return ExpensiveService(); // Called only on first access
});
Pattern: Testing with Mocks #
registry.register(IService, MockService());
final service = registry.getInstance<IService>();
// Test with mock
registry.destroyAll(); // Cleanup
Key Takeaways #
✅ Do:
- Use
lazyfor expensive resources - Check with
contains()before unsafe access - Use
replace()for updates, notregister()again - Call
destroy()anddestroyAll()for cleanup - Implement
IValueForRegistryfor custom destruction
❌ Don't:
- Register the same key twice (use
replace()) - Access without checking if unsure (
contains()) - Forget to call
destroyAll()in cleanup - Mix eager and lazy inappropriately
- Ignore error handling (catch
DuplicateRegistrationError,RegistryNotFoundError)
Questions? #
Check the main README.md for package documentation and API reference.