CODESAMPLE
Clean Architecture - Java
The Clean Architecture pattern aims to create systems independent of frameworks, databases, UI, and any external agency. It achieves this through layered architecture with an “inward rule” – dependencies point only inwards. The core business logic (Entities and Use Cases) resides in the inner layers, while outer layers (Interface Adapters & Frameworks and Drivers) contain implementation details. This promotes testability, maintainability, and flexibility.
The provided Java example demonstrates a simplified Clean Architecture for a user data management system. The entities package contains the User entity. usecases define the core business logic like RegisterUser. The interfaceadapters package features a UserPresenter which adapts data for presentation, and a UserGateway interface defining data access. Finally, frameworks includes a concrete UserRepository implementation using an in-memory data store and a simple CLI Main class acting as the driver. Dependency Injection is used to decouple layers. This structure aligns with Java’s packaging conventions and OOP principles, enhancing readability and scalability.
// entities/User.java
package entities;
public class User {
private final String username;
private final String email;
public User(String username, String email) {
this.username = username;
this.email = email;
}
public String getUsername() {
return username;
}
public String getEmail() {
return email;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", email='" + email + '\'' +
'}';
}
}
// usecases/RegisterUser.java
package usecases;
import entities.User;
import interfaces.UserGateway;
public class RegisterUser {
private final UserGateway userGateway;
public RegisterUser(UserGateway userGateway) {
this.userGateway = userGateway;
}
public boolean register(String username, String email) {
User newUser = new User(username, email);
return userGateway.saveUser(newUser);
}
}
// interfaceadapters/UserPresenter.java
package interfaceadapters;
import entities.User;
public class UserPresenter {
public static String presentUser(User user) {
return "Username: " + user.getUsername() + ", Email: " + user.getEmail();
}
}
// interfaces/UserGateway.java
package interfaces;
import entities.User;
public interface UserGateway {
boolean saveUser(User user);
User getUserByUsername(String username);
}
// frameworks/UserRepository.java
package frameworks;
import entities.User;
import interfaces.UserGateway;
import java.util.HashMap;
import java.util.Map;
public class UserRepository implements UserGateway {
private final Map<String, User> users = new HashMap<>();
@Override
public boolean saveUser(User user) {
if (users.containsKey(user.getUsername())) {
return false;
}
users.put(user.getUsername(), user);
return true;
}
@Override
public User getUserByUsername(String username) {
return users.get(username);
}
}
// frameworks/Main.java
package frameworks;
import usecases.RegisterUser;
public class Main {
public static void main(String[] args) {
UserRepository userRepository = new UserRepository();
RegisterUser registerUser = new RegisterUser(userRepository);
boolean registered = registerUser.register("john.doe", "john.doe@example.com");
if (registered) {
System.out.println("User registered successfully!");
} else {
System.out.println("User registration failed.");
}
}
}