← Back to list

Exploring Dependency Injection Patterns in Guice — Provider, AssistedInject, and Factory Modules

Introduction

Alexander Obregon · 2023-05-01 08:06 · 2 claps · 2.9 min read
#guice #google-guice #dependency-injection #provider-pattern #java
Open on Medium ↗

Exploring Dependency Injection Patterns in Guice — Provider, AssistedInject, and Factory Modules

Image Source

Image Source

Introduction

Dependency Injection is a design pattern that allows us to decouple the creation of objects from their usage. It helps us create more maintainable, testable, and modular code. In this article we will explore three dependency injection patterns in Guice: Provider, AssistedInject, and Factory Modules. We will also provide code examples to demonstrate the usage of each pattern.

Provider Pattern

The Provider pattern is a straightforward way to inject dependencies in Guice. A provider is a simple Java class that implements the Provider<T> interface, where T is the type of object it will provide. Providers are responsible for creating instances of the object they provide.

Code Example:

public class EngineProvider implements Provider<Engine> {
    @Override
    public Engine get() {
        return new V8Engine();
    }
}

public class Car {
    private final Engine engine;

    @Inject
    public Car(Engine engine) {
        this.engine = engine;
    }
}

public class CarModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Engine.class).toProvider(EngineProvider.class);
    }
}

In this example, we have an EngineProvider class that provides an instance of a V8Engine. The Car class has a dependency on the Engine interface, and the CarModule binds the Engine to the EngineProvider.

AssistedInject Pattern

The AssistedInject pattern allows you to mix automatically injected dependencies with manually provided arguments in a constructor. This pattern is useful when some dependencies cannot be resolved by the injector at runtime.

Code Example:

public class Car {
    private final Engine engine;
    private final String color;

    @AssistedInject
    public Car(Engine engine, @Assisted String color) {
        this.engine = engine;
        this.color = color;
    }
}

public interface CarFactory {
    Car create(String color);
}

public class CarModule extends AbstractModule {
    @Override
    protected void configure() {
        install(new FactoryModuleBuilder().implement(Car.class, Car.class).build(CarFactory.class));
    }
}

In this example, the Car class has an additional color field. We use the @AssistedInject annotation to indicate that the color parameter should be provided manually, while the Engine dependency should be injected automatically. We also define a CarFactory interface that allows us to create instances of Car with the specified color.

Factory Modules

Factory Modules provide a more flexible way to create instances of objects with complex dependencies or configuration. They use the AbstractFactory pattern, where an interface defines the factory methods for creating instances.

Code Example:

public interface EngineFactory {
    Engine create(String type);
}

public class EngineFactoryImpl implements EngineFactory {
    @Inject
    public EngineFactoryImpl() {}

    @Override
    public Engine create(String type) {
        switch (type) {
            case "V8":
                return new V8Engine();
            case "V6":
                return new V6Engine();
            default:
                throw new IllegalArgumentException("Unknown engine type: " + type);
        }
    }
}

public class CarModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(EngineFactory.class).to(EngineFactoryImpl.class);
    }
}

In this example, we have an EngineFactory interface and an implementation EngineFactoryImpl. The factory allows us to create different types of engines based on the provided type parameter. The CarModule binds the EngineFactory to the EngineFactoryImpl implementation.

With the Factory Modules pattern, you can create instances of objects that have complex dependencies or require dynamic configuration based on input parameters. This pattern is particularly useful when you have multiple implementations of an interface and you need to decide which one to use at runtime.

Code Example:

public class Car {
    private final Engine engine;

    @Inject
    public Car(EngineFactory engineFactory, @Named("engineType") String engineType) {
        this.engine = engineFactory.create(engineType);
    }
}

public class CarModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(String.class).annotatedWith(Names.named("engineType")).toInstance("V8");
        bind(EngineFactory.class).to(EngineFactoryImpl.class);
    }
}

In this example, the Car class has a dependency on the EngineFactory interface. It uses the factory to create an instance of the Engine based on the engineType parameter, which is injected using the @Named annotation. The CarModule binds the engineType parameter to the "V8" value and binds the EngineFactory to the EngineFactoryImpl implementation.

Conclusion

We have explored three dependency injection patterns in Guice: Provider, AssistedInject, and Factory Modules. Each pattern has its own advantages and is suitable for different scenarios:

  • Provider Pattern: A simple way to inject dependencies, suitable for most use cases.
  • AssistedInject Pattern: Allows mixing automatically injected dependencies with manually provided arguments, useful for constructors that require both.
  • Factory Modules: Provides a flexible way to create instances of objects with complex dependencies or configuration, suitable for cases where you need to decide which implementation to use at runtime.

By understanding and leveraging these patterns, you can create more maintainable, testable, and modular code with Guice.

  1. *Guice User Guide*
  2. *Dependency Injection Design Pattern*

메타데이터
post_id
fca6cdc4ab7e
slug
exploring-dependency-injection-patterns-in-guice-provider-assistedinject-and-factory-modules-fca6cdc4ab7e
url
https://medium.com/@AlexanderObregon/exploring-dependency-injection-patterns-in-guice-provider-assistedinject-and-factory-modules-fca6cdc4ab7e
canonical_url
https://medium.com/@AlexanderObregon/exploring-dependency-injection-patterns-in-guice-provider-assistedinject-and-factory-modules-fca6cdc4ab7e
author_url
https://medium.com/@AlexanderObregon
status
ok
fetched_at
2026-06-29 01:02:39