Skip to content

Factory Method

The Factory Method pattern delegates object creation to subclasses or specialized methods, allowing the type of created object to vary without modifying calling code. The caller works with the interface; the factory selects the concrete implementation.

classDiagram
    class VaultClientFactory {
        +Create() IVaultClient
    }

    class IVaultClient {
        <<interface>>
    }

    class KubernetesAuthClient
    class TokenAuthClient

    VaultClientFactory ..> IVaultClient : creates
    IVaultClient <|.. KubernetesAuthClient
    IVaultClient <|.. TokenAuthClient

    class ITenantIsolationStrategyProvider {
        +Create() DbContext
    }

    class SharedDatabaseDbContextFactory
    class TenantPerSchemaDbContextFactory
    class TenantPerDatabaseDbContextFactory

    ITenantIsolationStrategyProvider <|.. SharedDatabaseDbContextFactory
    ITenantIsolationStrategyProvider <|.. TenantPerSchemaDbContextFactory
    ITenantIsolationStrategyProvider <|.. TenantPerDatabaseDbContextFactory
FactoryFileSelection
VaultClientFactorysrc/Granit.Vault/Services/VaultClientFactory.csSwitch expression on AuthMethod (Kubernetes / Token)
SharedDatabaseDbContextFactorysrc/Granit.Persistence/MultiTenancy/SharedDatabaseDbContextFactory.csSharedDatabase strategy
TenantPerSchemaDbContextFactorysrc/Granit.Persistence/MultiTenancy/TenantPerSchemaDbContextFactory.csSchemaPerTenant strategy
TenantPerDatabaseDbContextFactorysrc/Granit.Persistence/MultiTenancy/TenantPerDatabaseDbContextFactory.csDatabasePerTenant strategy

Custom variant: the persistence factories combine Factory Method + Strategy — the strategy is selected at configuration time, and the factory creates the appropriate DbContext per request.

The choice of Vault authentication method (Kubernetes in production, Token in development) and tenant isolation strategy must be resolved at runtime without if/else in application code.

// The factory is resolved via DI -- calling code is unaware of the implementation
IVaultClient client = vaultClientFactory.Create();
SecretData secret = await client.V1.Secrets.KeyValue.V2
.ReadSecretAsync("app/database", cancellationToken: ct);