```html
🛠️ Dependency Injection (DI) in Java: Code Snippets
Dependency Injection is a design pattern that allows us to remove the tight coupling between software components. Here are examples of different ways to implement DI in Java:
1. 🏗️ Constructor Injection
Dependencies are provided through the class constructor.
public class MessageService {
private final MessageSender sender;
public MessageService(MessageSender sender) {
this.sender = sender;
}
public void sendMessage(String message) {
sender.send(message);
}
}
public class MessageSender {
public void send(String message) {
System.out.println("Sending message: " + message);
}
}
// Usage
MessageSender emailSender = new MessageSender();
MessageService service = new MessageService(emailSender);
service.sendMessage("Hello, world!");
2. ⚙️ Setter Injection
Dependencies are injected via setter methods.
public class UserService {
private UserRepository userRepository;
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUser(String userId) {
return userRepository.getUser(userId);
}
}
public class UserRepository {
public User getUser(String userId) {
// Implementation to fetch user from database
return new User(userId, "John Doe");
}
}
// Usage
UserService userService = new UserService();
userService.setUserRepository(new UserRepository());
User user = userService.getUser("123");
System.out.println(user.getName());
3. 🧲 Field Injection (Not Recommended)
Dependencies are injected directly into the class fields. Generally discouraged due to tight coupling and testing difficulties.
public class ProductService {
@Inject
private ProductRepository productRepository;
public Product getProduct(String productId) {
return productRepository.getProduct(productId);
}
}
public class ProductRepository {
public Product getProduct(String productId) {
// Implementation to fetch product from database
return new Product(productId, "Laptop");
}
}
// Usage - Requires a DI framework like Spring or Guice to inject the repository
// Example using reflection (not typical in production)
ProductService productService = new ProductService();
// Code to manually inject the dependency using reflection is complex and not shown here
4. 🧬 Interface Injection (Less Common)
Dependencies are injected through an interface.
public interface Injectable {
void setDependency(Dependency dependency);
}
public class Client implements Injectable {
private Dependency dependency;
@Override
public void setDependency(Dependency dependency) {
this.dependency = dependency;
}
public void doSomething() {
dependency.execute();
}
}
public class Dependency {
public void execute() {
System.out.println("Dependency executed");
}
}
// Usage
Client client = new Client();
Dependency dependency = new Dependency();
client.setDependency(dependency);
client.doSomething();
💡 Key Takeaways
- Constructor Injection: Promotes immutability and ensures dependencies are available upon object creation.
- Setter Injection: Allows optional dependencies and late configuration.
- Field Injection: Simplifies the injection process but can lead to tight coupling and hidden dependencies.
- Interface Injection: Provides a flexible way to inject dependencies via interfaces.
Choose the injection type that best fits your design requirements and consider using a DI framework like Spring or Guice for more complex applications.