Use Case / Interactor Pattern in Java
Fast recall
Quick revision
Core answer
PlaceOrderUseCase, RefundOrderUseCase. It receives a request DTO (or arguments), orchestrates entities and gateways, and returns a response DTO. Each use case has one public method (execute/handle/place), depends on interfaces (ports) it owns, and contains no framework code. This makes use cases unit-testable in isolation, callable from any input adapter (HTTP, Kafka, CLI), and the natural unit of granularity for an application.Use case as one-class-one-goal, the input/output DTO model, dependency injection via constructor, and how use cases differ from a traditional Spring @Service.
Use cases that handle HTTP concerns directly, or 'fat' use cases that do five unrelated things, or shoving all CRUD into one 'OrderService' use case.
Discuss input/output ports (Cockburn's terminology), command vs query use cases, transaction boundaries on use cases, and the trade-off vs traditional service classes.
Interview-ready guide
Interview answer
What a use case is
One user goal: 'Place an order', 'Refund an order'. The unit of application behavior the business cares about.
In code: one class per use case, one public method named after the verb, dependencies (repositories, gateways) injected via constructor, pure Java without Spring annotations on the class itself.
Compared to traditional Spring @Service: an OrderService typically has 10 methods (place, cancel, refund, ...). A use case set has 10 classes. More files, but each does one thing with explicit dependencies, tests in isolation.
Skeleton
Input port: PlaceOrderUseCase interface with one method. Input DTO (command): PlaceOrderCommand record with customerId, items, idempotencyKey. Output DTO: PlaceOrderResponse with orderId, total, placedAt. Output ports: OrderRepository, InventoryGateway interfaces owned by the use case layer. Implementation: PlaceOrderInteractor implements PlaceOrderUseCase, depends on the ports via constructor.
Logic: idempotency check, domain logic via entities, persist. Zero Spring imports. Wired by @Configuration, called by @RestController adapter.
Adapters around it
Same use case can be called from REST controller (HTTP request → build command → placeOrder.place(cmd) → response) or from Kafka consumer (event → build command → placeOrder.place(cmd)). The use case doesn't care which one called it.
Command vs query use cases
Command use cases (mutate state): PlaceOrderUseCase, RefundOrderUseCase. Often transactional. Return minimal output.
Query use cases (read-only): GetOrderHistoryUseCase, SearchOrdersUseCase. @Transactional(readOnly=true). Return rich DTOs tailored to the query. Can bypass domain model for performance, query directly against read models.
Separation prevents 'OrderService' from becoming a 50-method beast.
Transactions on use cases
Use case is the natural transaction boundary: one user goal = one business transaction.
Pattern A: AOP/proxy wrap in @Configuration. Pure but heavier. Pattern B (pragmatic): @Transactional on the implementation. Less pure but commonly accepted. Pattern C (purist): UnitOfWork interface in inner layer; Spring-backed implementation in adapter.
Boundary is the use case, not the controller and not the repository.
Testing
Dependencies are interfaces, class is plain Java. Test with in-memory port implementations. No Spring context. No DB. No Testcontainers. Tests run in milliseconds.
Common mistakes
- Use case takes HttpServletRequest — couples to HTTP; use plain command DTO
- Multiple methods per use case — just OrderService in disguise; split
- Use case calls another use case directly — sometimes OK, often a missing domain service
- No DTO at boundary — returning JPA/domain entity bypasses adapter responsibility
- Spring annotations on use case class — framework-coupled
- Use cases for trivial CRUD — GetUserById is just userRepo.findById; wrapping is ceremony without value
Recommendation
Use the Use Case pattern when business logic is non-trivial, when multiple input adapters share the same operation, or when fast pure-unit testability is critical. One class per user goal, command + response DTOs, depend on inner-owned ports, wire with @Configuration, transactions at the use case boundary. For trivial CRUD operations the wrapper is overhead — a controller calling a repository directly is fine. Reserve use cases for behavior that has real orchestration, validation, or side effects worth isolating.
Use Case / Interactor Pattern in Java
Direct Answer
A Use Case (also called an Interactor) is a class that encapsulates one application-specific user goal — e.g., PlaceOrderUseCase, RefundOrderUseCase. It receives a request DTO (or arguments), orchestrates entities and gateways, and returns a response DTO. Each use case has one public method (execute/handle/place), depends on interfaces (ports) it owns, and contains no framework code. This makes use cases unit-testable in isolation, callable from any input adapter (HTTP, Kafka, CLI), and the natural unit of granularity for an application.
Common Mistakes & Pitfalls
Use cases that handle HTTP concerns directly, or 'fat' use cases that do five unrelated things, or shoving all CRUD into one 'OrderService' use case.
Check your understanding
Answer these without looking back at the article.
- When is wrapping a CRUD operation in a use case overkill?
- How do you handle a use case that calls another use case?
- Where do you put @Transactional in a Clean Architecture project?
- Show how the same use case is invoked from a REST endpoint and a Kafka consumer.
Related interview prep categories
1Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.