An interface describes methods an implementation must provide. A service can depend on the contract without knowing the concrete technology. Composition means objects receive the helpers they need and collaborate with them. The same workflow can therefore use different storage on desktop and server.
01Name a contract
JobStore provides save. The contract describes the task rather than SQL or a file. ConsoleStore implements it and merely prints the result.
public class Main {
interface JobStore { void save(String id); }
static final class ConsoleStore implements JobStore {
public void save(String id) { System.out.println("Saved: " + id); }
}
static final class BatchService {
private final JobStore store;
BatchService(JobStore store) { this.store = store; }
void create(String id) { store.save(id); }
}
public static void main(String[] args) {
new BatchService(new ConsoleStore()).create("job-1");
}
}
Run / check
java Main.java02Pass the dependency
BatchService receives JobStore in its constructor. The caller decides which implementation to use. The service does not secretly create a database adapter. This makes focused testing easier.
03Read the boundary realistically
The sample implementation persists nothing. It only demonstrates that the service works through a replaceable contract. PDF Batch Studio uses real repository adapters and also defines state and error rules.
Saved: job-1
Your exercise
Create a MemoryStore implementation keeping IDs in an ArrayList. Does BatchService need to change?
Show the solution and explanation
MemoryStore implements the same save method and adds the ID to a list. BatchService stays unchanged. Only the wiring in main uses the new store. The shared interface enables the replacement.
Project context and sources
The example is simplified for learning. The linked source version shows its use in the project and the checks applied there.