-
public interface BorgDrone<T extends Object, C extends Object>Contract for components that need ordered, dependency-aware initialization.
Why an interface?
Keeps initialization logic separate from component business logic
Makes dependencies explicit through the type system
Allows mocking in tests
Generic context parameter allows flexibility in initialization
Example implementations:
// 1. Simple configuration drone class ConfigDrone : BorgDrone<AppConfig, Context> { override suspend fun assimilate(context: Context, borg: Borg<Context>): AppConfig { return AppConfig.load(context.assets.open("config.json")) } } // 2. Database initialization with config dependency class DatabaseDrone(private val configDrone: ConfigDrone) : BorgDrone<Database, Context> { override fun requiredDrones() = listOf(configDrone::class.java) override suspend fun assimilate(context: Context, borg: Borg<Context>): Database { val config = borg.requireAssimilated(configDrone::class.java) return Room.databaseBuilder(context, Database::class.java, config.dbName) .build() } } // 3. Repository with multiple dependencies class RepositoryDrone( private val databaseDrone: DatabaseDrone, private val apiDrone: ApiDrone ) : BorgDrone<Repository, Context> { override fun requiredDrones() = listOf( databaseDrone::class.java, apiDrone::class.java ) override suspend fun assimilate(context: Context, borg: Borg<Context>): Repository { val db = borg.requireAssimilated(databaseDrone::class.java) val api = borg.requireAssimilated(apiDrone::class.java) return Repository(db, api) } } // 4. Analytics with fallback handling class AnalyticsDrone : BorgDrone<Analytics, Context> { override suspend fun assimilate(context: Context, borg: Borg<Context>): Analytics { return try { FirebaseAnalytics.getInstance(context) } catch (e: Exception) { NoOpAnalytics() // Fallback implementation } } }Best practices:
Keep drones focused and single-purpose
Make dependencies explicit in constructor
Handle errors gracefully with fallbacks
Use meaningful names that reflect purpose
Document any special initialization requirements
Consider thread safety in returned objects
Cache expensive operations appropriately
Write unit tests for initialization logic
-
-
Method Summary
Modifier and Type Method Description List<Class<out BorgDrone<?, C>>>requiredDrones()Declares initialization prerequisites. abstract Tassimilate(C context, Borg<C> borg)Creates and configures a component instance. -
-
Method Detail
-
requiredDrones
List<Class<out BorgDrone<?, C>>> requiredDrones()
Declares initialization prerequisites.
Why a list?
Natural representation of multiple dependencies
Order doesn't matter (Borg handles sequencing)
Empty by default for leaf components
Best practices:
List ALL required dependencies
Use constructor injection for dependencies
Keep dependency count low (ideally ≤ 3)
Document why each dependency is needed
Consider breaking up drones with many dependencies
Example:
override fun requiredDrones() = listOf( configDrone::class.java, // For API configuration authDrone::class.java, // For authentication tokens logDrone::class.java // For request logging )
-
assimilate
abstract T assimilate(C context, Borg<C> borg)
Creates and configures a component instance.
Contract:
Must be idempotent (same result for multiple calls)
Should complete initialization fully or fail fast
May access results of required drones via borg
Should return immutable or thread-safe result
Best practices:
Validate inputs and dependencies early
Handle errors gracefully with fallbacks
Log important initialization steps
Clean up resources on failure
Keep initialization logic simple
Document any assumptions or requirements
Example error handling:
override suspend fun assimilate(context: C, borg: Borg<C>): T { try { // 1. Get dependencies val config = borg.requireAssimilated(configDrone::class.java) // 2. Validate configuration require(config.isValid) { "Invalid configuration" } // 3. Initialize component return MyComponent(config) .also { it.initialize() } } catch (e: Exception) { // 4. Clean up on failure cleanup() throw BorgException.AssimilationException( drone = this::class.java, cause = e ) } }- Parameters:
context- The context object needed for initializationborg- The Borg instance, providing access to assimilated drone values
-
-
-
-