Domain Interface Design and Its Application in Backend Systems
The article explains how designing domain models as interfaces, rather than concrete classes, improves flexibility in backend architectures by simplifying data exchange, supporting multiple persistence technologies, and enabling seamless deployment across standalone, clustered, and micro‑service environments.
Designing domain models as interfaces instead of concrete classes is a common practice for service and repository layers, but a deeper understanding of full interface‑based design—especially for domain models—can greatly enhance flexibility and maintainability.
Typical domain models are classes; however, they can be defined as interfaces, e.g.:
public interface User { /* ... */ } public class UserImpl implements User { /* ... */ }When using JPA, a repository implementation might look like:
public class JpaUserRepository implements UserRepository { @Override public Optional
findById(String id) { UserPO userPO = this.entityManager.find(UserPO.class, id); return Optional.ofNullable(userPO).map(UserPO::toUser); } @Override public User save(User user) { UserPO userPO = this.entityManager.find(UserPO.class, user.getId()); userPO.setNickname(user.getNickname()); return this.entityManager.merge(userPO).toUser(); } }Because the User is an interface, the data‑exchange overhead of converting between PO and domain objects can be reduced by returning concrete interface implementations directly.
For repositories that rely on specific generic types (e.g., Spring Data Elasticsearch), the interface‑based approach is not directly supported, so a delegating repository is used:
public class DelegatingElasticsearchUserRepository implements UserRepository { private final ElasticsearchUserRepository elasticsearchUserRepository; public DelegatingElasticsearchUserRepository(ElasticsearchUserRepository repo) { this.elasticsearchUserRepository = repo; } @Override public User create(String id) { return new ElasticsearchUser(id); } @Override public Optional
findById(String id) { return CastUtils.cast(this.elasticsearchUserRepository.findById(id)); } @Override public User save(User user) { return this.elasticsearchUserRepository.save(ElasticsearchUser.of(user)); } }When persisting entities that contain interface‑typed collections, JPA cannot infer the concrete type. The targetEntity attribute solves this problem for associations such as @OneToMany , @OneToOne , @ManyToOne , and @ManyToMany :
@OneToMany(targetEntity = JpaOrderItem.class) private List
items = new ArrayList<>();If the persistence framework does not support targetEntity , encapsulation or explicit mapping (e.g., MyBatis resultMap ) can be used to bind interface collections to concrete classes.
Creating domain objects also shifts from using the new operator to factory methods provided by application services, e.g.:
@Test public void testCreateUser() { User user = this.userService.createUser(null); user.setNickname("Nickname"); user.setGender(Gender.MALE); this.userService.addUser(user); }System‑level interface design further enables seamless switching between standalone, clustered, and micro‑service deployments. By exposing domain interfaces through separate modules (e.g., user-api , user-openfeign-client , user-rest-client ), the same business code can run in different environments without modification.
The open‑source Mallfoundry project exemplifies these principles: it is a Spring Boot‑based multi‑tenant e‑commerce platform that adopts DDD, interface‑based design, and modular architecture, allowing it to run as a library, a server, a cluster, or a cloud service.
In summary, interface‑based domain modeling creates a unified contract for business logic, simplifies persistence across various data sources, and prepares the system for future architectural changes, though it demands higher expertise from developers and architects.
IT Architects Alliance
Discussion and exchange on system, internet, large‑scale distributed, high‑availability, and high‑performance architectures, as well as big data, machine learning, AI, and architecture adjustments with internet technologies. Includes real‑world large‑scale architecture case studies. Open to architects who have ideas and enjoy sharing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.