Service factories

When requesting dependencies, the implementations may differ for various contexts. DiVine lets you specify factories, which have the purpose of creating instances based on the given parameters.

You can bind a factory for a service directly.

@Service(factory = MyFactory.class)
class MyService { ... }

You can define your factory somewhere.

class MyFactory implements Factory<MyService, MyProperty> { ... }

The factory properties may differ depending on your use case.

class MyFactory implements Factory<MyService, String> { ... }
class MyFactory implements Factory<MyService, MyEnum> { ... }

... and so on.

When requesting a dependency for a service, you must also pass in the properties, as specified by the service.

@Service(factory = CoolFactory.class)
interface AmazingService { ... }
class CoolFactory implements Factory<AmazingService, String> { ... }
void requestDependency() {
    AmazingService service = Container.get(AmazingService, "EXAMPLE_PARAMETER");
}

Note that parameter arguments are checked at runtime, so factory types are guaranteed inside the factory class.

The following code showcases a simple way of requesting different implementations for a service.

@Service(
    // use the `CarFactory` class to create new instances for the `Car` type
    factory = CarFactory.class,
    // use `TRANSIENT` scope, to create a new car instance, each time a car 
    // is requested
    scope = ServiceScope.TRANSIENT 
)
interface Car {
    void drive();
}

enum CarType {
    MERCEDES,
    BMW,
    FERRARI
}

class CarFactory implements Factory<
    Car, 
    CarType // you may specify any arbitrary factoryparameter type
> {
    @Override
    public @NotNull Car create(
        @NotNull Service descriptor, @NotNull Class<? extends Car> type, 
        @NotNull Class<?> context, @Nullable CarType carType
    ) {
        return switch (carType) {
            case MERCEDES -> new MercedesCar();
            case BMW -> new BMWCar();
            case FERRARI -> new FerrariCar();
        };
    }
}

@Service
class CarDealership() {
    public Car orderCar(CarType type) {
        return Container.get(Car.class, type);
    }
}

void orderCars() {
    CarDealership dealership = Container.get(CarDealership.class);
    assert dealership.orderCar(CarType.MERCEDES) instanceof MercedesCar;
    assert dealership.orderCar(CarType.BMW) instanceof BMWCar;
    assert dealership.orderCar(CarType.FERRARY) instanceof FerraryCar;
}

Last updated