← Back to Advanced Java Course | Chapter 6: Design Patterns | Lesson 14 of 14

Java Repository Pattern

The Repository pattern mediates between the domain model and a data storage mechanism, presenting a collection-like interface for accessing domain objects while hiding how they're actually persisted.

What is the Repository Pattern?

The Repository pattern mediates between the domain model and a data storage mechanism, presenting a collection-like interface for adding, retrieving, and removing domain objects while hiding exactly how or where they're actually persisted.

Example: What is the Repository Pattern?

java
import java.util.*;
public class Main {
	interface Repository<T> {
		void save(T item);
		List<T> findAll();
	}
	public static void main(String[] args) {
		System.out.println("Repository presents a collection-like interface over storage");
	}
}

Repository Interface

A repository interface typically defines standard operations like save, findById, findAll, and delete, often expressed generically so the same interface shape can be reused across different entity types.

Example: Repository Interface

java
import java.util.*;
public class Main {
	interface Repository<T> {
		void save(T item);
		Optional<T> findById(int id);
		List<T> findAll();
		void delete(int id);
	}
	public static void main(String[] args) {
		System.out.println("Same generic shape reused across entity types");
	}
}

In-Memory Repository Implementation

An in-memory repository implementation, backed by a simple Map or List, is a lightweight way to satisfy the repository interface during development or testing, without requiring a real database connection.

Example: In-Memory Repository Implementation

java
import java.util.*;
public class Main {
	interface Repository<T> { void save(T item); List<T> findAll(); }
	static class InMemoryUserRepository implements Repository<String> {
		List<String> users = new ArrayList<>();
		public void save(String item) { users.add(item); } // backed by a simple List
		public List<String> findAll() { return users; }
	}
	public static void main(String[] args) {
		Repository<String> repo = new InMemoryUserRepository();
		repo.save("Riya");
		System.out.println(repo.findAll());
	}
}

Database-Backed Repository

A database-backed repository implements the same interface using JDBC or another persistence technology to actually store and retrieve data from a relational database, while calling code remains unaware of the difference.

Example: Database-Backed Repository

java
import java.util.*;
public class Main {
	interface Repository<T> { void save(T item); List<T> findAll(); }
	static class JdbcUserRepository implements Repository<String> {
		List<String> simulatedTable = new ArrayList<>(); // stand-in for a real JDBC-backed store
		public void save(String item) { simulatedTable.add(item); } // real version would run an INSERT
		public List<String> findAll() { return simulatedTable; } // real version would run a SELECT
	}
	public static void main(String[] args) {
		Repository<String> repo = new JdbcUserRepository();
		repo.save("Aman");
		System.out.println(repo.findAll());
	}
}

Repository with Spring Data JPA

Spring Data JPA takes the Repository pattern further by generating a working implementation automatically from just an interface definition, even deriving database queries directly from specially named methods like findByName.

Example: Repository with Spring Data JPA

java
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public class Main {
	static class User { String name; }
	interface UserRepository extends JpaRepository<User, Long> {
		List<User> findByName(String name); // implementation generated automatically
	}
	public static void main(String[] args) {
		System.out.println("Spring Data JPA generates the implementation from the interface alone");
	}
}

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.