Clean Architecture
================================ =
Clean Architecture is an architectural style and design pattern for software development that emphasizes Separation Of Concerns, Testability, and Maintainability. It was first introduced by Robert C. Martin (aka “Uncle Bob”) in his 2008 book “Clean Architecture: A Craftsman’s Guide to Software Structure and Design”.
Overview
Clean Architecture is a holistic approach to software design that involves three main layers:
- Entities: Represent business domains, such as Users, products, or orders.
- Use Cases: Define the interactions between entities and the outside world.
- Interface Adapters: Provide a standardized interface for interacting with external systems.
Layers
1. Entities
- Represent business domains, such as Users, products, or orders.
- These entities are self-contained and have their own logic.
- Entities typically contain Domain Logic and are encapsulated within the Entity class.
2. Use Cases
- Define the interactions between entities and the outside world.
- Use cases describe the desired behavior of the system in terms of actions to be performed on entities or objects.
- Use cases should be clear, concise, and easy to understand.
3. Interface Adapters
- Provide a standardized interface for interacting with external systems.
- Interface adapters map Interfaces to specific Implementation Details.
- Interface adapters are used to decouple the business logic from the external systems.
Benefits
- Separation Of Concerns: Clean Architecture promotes Separation Of Concerns between entities, use cases, and interface adapters.
- Testability: Entities can be tested independently, making it easier to identify and fix defects.
- Maintainability: Changes to one part of the system do not affect other parts.
- Flexibility: Interface adapters allow for easy changes in external systems without affecting entities.
Components
1. Entities
<a href="/User" class="missing-article">User</a>: represents a User Entity[Product](/Product): represents a Product Entity<a href="/Order" class="missing-article">Order</a>: represents an Order Entity
2. Use Cases
GetUsers()GetProducts()PlaceOrder()
3. Interface Adapters
UserRepository: provides a standardized interface for interacting with Users (e.g., Database or File-Based Storage)ProductRepository: provides a standardized interface for interacting with productsOrderService: provides a standardized interface for interacting with orders
Example Use Case
Suppose we have an E-commerce System with the following entities and use cases:
Entities
<a href="/User" class="missing-article">User</a>[Product](/Product)
Use Cases
GetUsers(): returns a list of UsersGetProducts(): returns a list of productsPlaceOrder(): creates a new Order for a Product
Interface Adapters
UserRepository: provides an interface for retrieving User data from a DatabaseProductRepository: provides an interface for retrieving Product data from a File-Based StorageOrderService: provides an interface for creating and managing orders
Implementation
The Clean Architecture approach involves the following steps:
- Entities: Define the business domain entities.
- Use Cases: Create use cases that describe the desired behavior of the system.
- Interface Adapters: Develop interface adapters to map Interfaces to specific Implementation Details.
Example Implementation
// <a href="/User" class="missing-article">User</a> [Entity](/Entity)
public class <a href="/User" class="missing-article">User</a> {
private int id;
private String name;
// getters and setters
}
// UserRepository interface
public interface UserRepository {
List<<a href="/User" class="missing-article">User</a>> getUsers();
void saveUser(<a href="/User" class="missing-article">User</a> <a href="/User" class="missing-article">User</a>);
}
// UserService class
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List<<a href="/User" class="missing-article">User</a>> getUsers() {
return userRepository.getUsers();
}
}
// [Product](/Product) [Entity](/Entity)
public class [Product](/Product) {
private int id;
private String name;
// getters and setters
}
// ProductRepository interface
public interface ProductRepository {
List<[Product](/Product)> getProducts();
void saveProduct([Product](/Product) [Product](/Product));
}
// ProductService class
public class ProductService {
private final ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public List<[Product](/Product)> getProducts() {
return productRepository.getProducts();
}
}
// OrderService interface
public interface OrderService {
void createOrder(<a href="/Order" class="missing-article">Order</a> <a href="/Order" class="missing-article">Order</a>);
}
// OrderServiceImpl class
public class OrderServiceImpl implements OrderService {
private final UserRepository userRepository;
private final ProductRepository productRepository;
public OrderServiceImpl(UserRepository userRepository, ProductRepository productRepository) {
this.userRepository = userRepository;
this.productRepository = productRepository;
}
@Override
public void createOrder(<a href="/Order" class="missing-article">Order</a> <a href="/Order" class="missing-article">Order</a>) {
// logic to create an <a href="/Order" class="missing-article">Order</a>
}
}
By following the Clean Architecture approach, developers can create maintainable, testable, and scalable software systems that are easier to understand and extend.