The DAO or the Data Access Object pattern is a very popular structural design pattern that separates the persistence logic in a separate layer. The idea is to abstract or hide the database logic from the business layer. It helps in hiding unnecessary CRUD operation and storage details from our service layer so that it can evolve independently. This is also known as ‘Separation of concerns’ principle.
In this tutorial, we’ll learn to implement Java DAO pattern with the help of an example.
In the DAO design pattern, we usually have the following components:
To follow along with this tutorial, let’s say we have an application which operates on Employee details. On using the DAO pattern, our application structure would be similar to:
Here, EmployeeDao is an interface providing an abstraction over the persistence logic present in EmployeeDaoImpl class. Our business layer will only interact with the persistence layer using the EmployeeDao interface. In this way, the two layers remain de-coupled and the business layer doesn’t need to know the complex details involved in persistence.
Let’s start by defining our Employee class:
public class Employee { private int id; private String name; //constructor, equals() & toString() impl, getters and setters }
It’s a simple POJO representing an Employee in our application.
We’ll now define our EmployeeDao interface, which will abstract the details of our class holding concrete implementation of the persistence logic:
public interface EmployeeDao { public List<Employee> getAllEmployees(); public Optional<Employee> getEmployeeById(int id); public void save(Employee emp); public void delete(Employee emp); public void updateEmpName(Employee emp, String name); }
Here, we have defined the CRUD operations that’ll be exposed to our business layer.
Having defined our EmployeeDao interface, let’s implement it:
public class EmployeeDaoImpl implements EmployeeDao { private List<Employee> employees; public EmployeeDaoImpl() { employees.add(new Employee(1, "Harry")); employees.add(new Employee(2, "Kathy")); employees.add(new Employee(3, "Simens")); } @Override public List<Employee> getAllEmployees() { return employees; } @Override public Optional<Employee> getEmployeeById(int id) { Employee emp = null; for(Employee e : employees) { if(e.getId() == id) { emp = e; break; } } return Optional.ofNullable(emp); } @Override public void save(Employee emp) { employees.add(emp); } @Override public void delete(Employee emp) { employees.remove(emp); } @Override public void updateEmpName(Employee emp, String name) { for(Employee e : employees) { if(e.equals(emp)) { //if employee exists e.setName(name); break; } } } }
In the above implementation, just for the sake of simplicity, we have used an ArrayList as a data store instead of interacting with some DB. Here, we make sure that we have overridden the equals() method in our Employee class correctly.
In real-world, in any DAO class, we’ll usually be interacting with some database.
Now, let’s try to perform some operations on our data store using the created persistence layer:
public class EmployeeApp { private static EmployeeDao employeeDao; public static void main(String[] args) { employeeDao = new EmployeeDaoImpl(); List<Employee> employees = employeeDao.getAllEmployees(); System.out.println(employees); Employee jessica = new Employee(4, "Jessica"); employeeDao.save(jessica); Optional<Employee> jessicaOpt = employeeDao.getEmployeeById(4); jessicaOpt.ifPresent(System.out::println); employeeDao.update(jessica, "Jessica S."); System.out.println(employees); } }
Our EmployeeDaoImpl class supports search, insert, update and delete operations. The business layer remains unaware of the actual persistence logic.
There are several advantages of using DAO Pattern:
In this tutorial, we learned to implement DAO Pattern in Java. It helps us to have a clear boundary between our persistence and business layers, promoting loose-coupling.
Thank you. Very helpful article.
Thanks 🙂