|
|
@@ -0,0 +1,319 @@
|
|
|
+# Usage Examples
|
|
|
+
|
|
|
+## Overview
|
|
|
+Practical examples demonstrating Inversion IoC container features including basic registration, lifecycle management, field injection, multi-registration, and scope-local registrations.
|
|
|
+
|
|
|
+## Basic Registration and Resolution
|
|
|
+
|
|
|
+```vala
|
|
|
+using Inversion;
|
|
|
+
|
|
|
+public interface ILogger : Object {
|
|
|
+ public abstract void log(string message);
|
|
|
+}
|
|
|
+
|
|
|
+public class ConsoleLogger : Object, ILogger {
|
|
|
+ public void log(string message) {
|
|
|
+ stdout.printf("[LOG] %s\n", message);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public static int main(string[] args) {
|
|
|
+ var container = new Container();
|
|
|
+
|
|
|
+ // Register implementation as interface
|
|
|
+ container.register_singleton<ConsoleLogger>((scope) => new ConsoleLogger())
|
|
|
+ .as_type(typeof(ILogger));
|
|
|
+
|
|
|
+ // Create scope and resolve
|
|
|
+ var scope = container.create_scope();
|
|
|
+ var logger = scope.resolve<ILogger>();
|
|
|
+ logger.log("Hello, World!");
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## Lifecycle Patterns
|
|
|
+
|
|
|
+### Singleton (Application-Wide)
|
|
|
+```vala
|
|
|
+public class Configuration : Object {
|
|
|
+ public string db_path { get; set; }
|
|
|
+}
|
|
|
+
|
|
|
+container.register_singleton<Configuration>((s) => {
|
|
|
+ var config = new Configuration();
|
|
|
+ config.db_path = "/data/app.db";
|
|
|
+ return config;
|
|
|
+});
|
|
|
+
|
|
|
+// Same instance across all scopes
|
|
|
+var scope1 = container.create_scope();
|
|
|
+var scope2 = container.create_scope();
|
|
|
+var config1 = scope1.resolve<Configuration>();
|
|
|
+var config2 = scope2.resolve<Configuration>();
|
|
|
+// config1 == config2
|
|
|
+```
|
|
|
+
|
|
|
+### Scoped (Per-Request)
|
|
|
+```vala
|
|
|
+public class UserSession : Object {
|
|
|
+ public string user_id { get; set; }
|
|
|
+}
|
|
|
+
|
|
|
+container.register_scoped<UserSession>((s) => new UserSession());
|
|
|
+
|
|
|
+// Same instance within scope
|
|
|
+var scope = container.create_scope();
|
|
|
+var session1 = scope.resolve<UserSession>();
|
|
|
+var session2 = scope.resolve<UserSession>();
|
|
|
+// session1 == session2
|
|
|
+
|
|
|
+// Different instance in different scope
|
|
|
+var other_scope = container.create_scope();
|
|
|
+var session3 = other_scope.resolve<UserSession>();
|
|
|
+// session1 != session3
|
|
|
+```
|
|
|
+
|
|
|
+### Transient (Per-Resolution)
|
|
|
+```vala
|
|
|
+public class RequestHandler : Object {
|
|
|
+ public void handle(string request) {
|
|
|
+ stdout.printf("Handling: %s\n", request);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+container.register_transient<RequestHandler>((s) => new RequestHandler());
|
|
|
+
|
|
|
+var scope = container.create_scope();
|
|
|
+var handler1 = scope.resolve<RequestHandler>();
|
|
|
+var handler2 = scope.resolve<RequestHandler>();
|
|
|
+// handler1 != handler2
|
|
|
+```
|
|
|
+
|
|
|
+## Field Injection
|
|
|
+
|
|
|
+```vala
|
|
|
+public interface IRepository : Object {
|
|
|
+ public abstract string get_data();
|
|
|
+}
|
|
|
+
|
|
|
+public interface IHandler : Object {
|
|
|
+ public abstract void handle(string request);
|
|
|
+}
|
|
|
+
|
|
|
+public class UserService : Object {
|
|
|
+ // Dependencies injected during construction
|
|
|
+ private IRepository repo = inject<IRepository>();
|
|
|
+ private IHandler handler = inject<IHandler>();
|
|
|
+
|
|
|
+ public void process() {
|
|
|
+ var data = repo.get_data();
|
|
|
+ handler.handle(data);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Register dependencies
|
|
|
+container.register_singleton<MemoryRepository>((s) => new MemoryRepository())
|
|
|
+ .as_type(typeof(IRepository));
|
|
|
+container.register_singleton<ConsoleHandler>((s) => new ConsoleHandler())
|
|
|
+ .as_type(typeof(IHandler));
|
|
|
+container.register_scoped<UserService>((s) => new UserService());
|
|
|
+
|
|
|
+// Resolve - dependencies injected automatically
|
|
|
+var scope = container.create_scope();
|
|
|
+var service = scope.resolve<UserService>();
|
|
|
+service.process();
|
|
|
+```
|
|
|
+
|
|
|
+## Multiple Implementations
|
|
|
+
|
|
|
+```vala
|
|
|
+public interface IValidator : Object {
|
|
|
+ public abstract bool validate(Object obj);
|
|
|
+}
|
|
|
+
|
|
|
+public class EmailValidator : Object, IValidator {
|
|
|
+ public bool validate(Object obj) {
|
|
|
+ stdout.printf("Validating email...\n");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public class PhoneValidator : Object, IValidator {
|
|
|
+ public bool validate(Object obj) {
|
|
|
+ stdout.printf("Validating phone...\n");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Register multiple implementations
|
|
|
+container.register_singleton<EmailValidator>((s) => new EmailValidator())
|
|
|
+ .as_type(typeof(IValidator));
|
|
|
+container.register_singleton<PhoneValidator>((s) => new PhoneValidator())
|
|
|
+ .as_type(typeof(IValidator));
|
|
|
+
|
|
|
+// Resolve all implementations
|
|
|
+var scope = container.create_scope();
|
|
|
+var validators = scope.resolve_all<IValidator>();
|
|
|
+
|
|
|
+validators.iterate((obj) => {
|
|
|
+ var validator = (IValidator) obj;
|
|
|
+ validator.validate(data);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+## Inject All Pattern
|
|
|
+
|
|
|
+```vala
|
|
|
+public class ValidationService : Object {
|
|
|
+ // Inject all IValidator implementations
|
|
|
+ private Lot<IValidator> validators = inject_all<IValidator>();
|
|
|
+
|
|
|
+ public bool validate_all(Object obj) {
|
|
|
+ foreach (var validator in validators) {
|
|
|
+ if (!validator.validate(obj)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## Scope-Local Registrations
|
|
|
+
|
|
|
+```vala
|
|
|
+public class RequestContext : Object {
|
|
|
+ public string request_id { get; set; }
|
|
|
+ public string path { get; set; }
|
|
|
+}
|
|
|
+
|
|
|
+// Container has application-wide services
|
|
|
+var container = new Container();
|
|
|
+container.register_singleton<Database>((s) => new Database());
|
|
|
+
|
|
|
+// Each request creates a scope with request-specific context
|
|
|
+void handle_request(string request_id, string path) {
|
|
|
+ var scope = container.create_scope();
|
|
|
+
|
|
|
+ // Register request-specific context (only visible in this scope)
|
|
|
+ scope.register_local_scoped<RequestContext>((s) => {
|
|
|
+ var ctx = new RequestContext();
|
|
|
+ ctx.request_id = request_id;
|
|
|
+ ctx.path = path;
|
|
|
+ return ctx;
|
|
|
+ });
|
|
|
+
|
|
|
+ // Handlers can resolve RequestContext
|
|
|
+ var handler = scope.resolve<RequestHandler>();
|
|
|
+ handler.process();
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## Custom Factory with Dependencies
|
|
|
+
|
|
|
+```vala
|
|
|
+public class OrderService : Object {
|
|
|
+ private IOrderRepository repo;
|
|
|
+ private ILogger logger;
|
|
|
+
|
|
|
+ public OrderService(IOrderRepository repo, ILogger logger) {
|
|
|
+ this.repo = repo;
|
|
|
+ this.logger = logger;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+container.register_scoped<OrderService>((scope) => {
|
|
|
+ // Resolve dependencies from scope
|
|
|
+ var repo = scope.resolve<IOrderRepository>();
|
|
|
+ var logger = scope.resolve<ILogger>();
|
|
|
+ return new OrderService(repo, logger);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+## Multiple Interface Registration
|
|
|
+
|
|
|
+```vala
|
|
|
+public interface IRepository : Object {
|
|
|
+ public abstract Object? find(int id);
|
|
|
+}
|
|
|
+
|
|
|
+public interface ICache : Object {
|
|
|
+ public abstract void cache(Object obj);
|
|
|
+}
|
|
|
+
|
|
|
+public class CachedRepository : Object, IRepository, ICache {
|
|
|
+ public Object? find(int id) { return null; }
|
|
|
+ public void cache(Object obj) { }
|
|
|
+}
|
|
|
+
|
|
|
+// Register as both interfaces
|
|
|
+container.register_singleton<CachedRepository>((s) => new CachedRepository())
|
|
|
+ .as_type(typeof(IRepository))
|
|
|
+ .as_type(typeof(ICache));
|
|
|
+
|
|
|
+// Can resolve by either interface
|
|
|
+var scope = container.create_scope();
|
|
|
+var repo = scope.resolve<IRepository>();
|
|
|
+var cache = scope.resolve<ICache>();
|
|
|
+// Both point to same CachedRepository instance
|
|
|
+```
|
|
|
+
|
|
|
+## Error Handling
|
|
|
+
|
|
|
+```vala
|
|
|
+try {
|
|
|
+ var service = scope.resolve<IMyService>();
|
|
|
+ service.do_work();
|
|
|
+} catch (ContainerError.NOT_REGISTERED e) {
|
|
|
+ stderr.printf("Service not registered: %s\n", e.message);
|
|
|
+} catch (ContainerError.CYCLE_DETECTED e) {
|
|
|
+ stderr.printf("Circular dependency: %s\n", e.message);
|
|
|
+} catch (ContainerError.ILLEGAL_LIFECYCLE_COMBINATION e) {
|
|
|
+ stderr.printf("Lifecycle error: %s\n", e.message);
|
|
|
+} catch (Error e) {
|
|
|
+ stderr.printf("Error: %s\n", e.message);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## Web Application Pattern
|
|
|
+
|
|
|
+```vala
|
|
|
+public class ApplicationController : Object {
|
|
|
+ private static Container container;
|
|
|
+
|
|
|
+ static construct {
|
|
|
+ container = new Container();
|
|
|
+
|
|
|
+ // Application-wide services
|
|
|
+ container.register_singleton<Database>((s) => new Database("app.db"));
|
|
|
+ container.register_singleton<Cache>((s) => new RedisCache());
|
|
|
+
|
|
|
+ // Per-request services
|
|
|
+ container.register_scoped<UserSession>((s) => new UserSession());
|
|
|
+ container.register_transient<RequestHandler>((s) => new RequestHandler());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void handle_request(Request req, Response res) {
|
|
|
+ var scope = container.create_scope();
|
|
|
+
|
|
|
+ // Register request context
|
|
|
+ scope.register_local_scoped<RequestContext>((s) => {
|
|
|
+ return new RequestContext(req.id, req.path);
|
|
|
+ });
|
|
|
+
|
|
|
+ try {
|
|
|
+ var handler = scope.resolve<RequestHandler>();
|
|
|
+ handler.handle(req, res);
|
|
|
+ } catch (Error e) {
|
|
|
+ res.error(500, e.message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+These examples demonstrate Inversion IoC patterns including basic registration, lifecycle management, field injection with inject<T>(), multi-registration with resolve_all<T>(), and scope-local registrations for per-request contexts.
|