🚀 Oferta especial: 60% OFF no CrazyStack - Últimas vagas!Garantir vaga →
Java

Como trabalhar com interfaces no Java e Spring Boot

Veja como usar interfaces de forma eficaz em projetos com Java e Spring Boot, passando pela estrutura DAO até JPA Repository

CrazyStack
12 min de leitura
JavaSpring BootInterfaces

Por que isso é importante

Interfaces são um dos pilares da programação orientada a objetos em Java. Quando aplicadas em projetos com Spring Boot, elas tornam o código mais escalável, testável e aderente ao princípio da inversão de dependência. Entender seu funcionamento vai além de decorá-las: é preciso compreender seu comportamento, especialmente no contexto de persistência com JPA Repository.

Estrutura tradicional Java sem Spring Boot

Antes do Spring Boot, era comum organizar o backend Java usando estrutura MVC dividida em pacotes como model, dao e connection factory.

Cada entidade ou tabela do sistema possuía uma classe model e uma classe DAO. Vamos ver um exemplo prático:

public class UsuarioModel {
    private Long id;
    private String nome;
    private String email;
    
    // Construtores
    public UsuarioModel() {}
    
    public UsuarioModel(String nome, String email) {
        this.nome = nome;
        this.email = email;
    }
    
    // Getters e Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getNome() { return nome; }
    public void setNome(String nome) { this.nome = nome; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}
public class UsuarioDAO {
    private Connection connection;
    
    public UsuarioDAO(Connection connection) {
        this.connection = connection;
    }
    
    public void insert(UsuarioModel usuario) throws SQLException {
        String sql = "INSERT INTO usuarios (nome, email) VALUES (?, ?)";
        PreparedStatement stmt = connection.prepareStatement(sql);
        stmt.setString(1, usuario.getNome());
        stmt.setString(2, usuario.getEmail());
        stmt.executeUpdate();
    }
    
    public List<UsuarioModel> selectAll() throws SQLException {
        String sql = "SELECT * FROM usuarios";
        PreparedStatement stmt = connection.prepareStatement(sql);
        ResultSet rs = stmt.executeQuery();
        
        List<UsuarioModel> usuarios = new ArrayList<>();
        while (rs.next()) {
            UsuarioModel usuario = new UsuarioModel();
            usuario.setId(rs.getLong("id"));
            usuario.setNome(rs.getString("nome"));
            usuario.setEmail(rs.getString("email"));
            usuarios.add(usuario);
        }
        return usuarios;
    }
    
    public void delete(Long id) throws SQLException {
        String sql = "DELETE FROM usuarios WHERE id = ?";
        PreparedStatement stmt = connection.prepareStatement(sql);
        stmt.setLong(1, id);
        stmt.executeUpdate();
    }
}

⚠️Problema

O excesso de código repetido entre DAOs (insert, select, delete) fez surgir a necessidade de padronização com interfaces genéricas.

Por que criar interfaces?

Interfaces funcionam como contratos: determinam quais métodos uma classe deverá implementar. Isso evita que cada DAO crie métodos soltos e inconsistentes.

Por exemplo, em vez de duplicar métodos como selectAll(), insert() e delete() em várias classes, uma GenericDAO define a estrutura base para todos os DAOs do sistema.

Passo a passo: Implementando DAO com Interface

1
Passo 1: Crie sua classe Model (ex: UsuarioModel) com atributos e métodos getters.
2
Passo 2: Crie a classe DAO (ex: UsuarioDAO) com os métodos do CRUD manualmente.
3
Passo 3: Crie uma interface genérica (GenericDAO) que contenha todos os métodos comuns que os DAOs devem implementar.
4
Passo 4: Faça cada DAO implementar a interface e obrigar o uso dos mesmos métodos definidos.

Reaproveitamento com interfaces genéricas

Uma interface genérica como GenericDAO<T> permite que múltiplas classes DAO compartilhem padrão sem repetir código, mantendo a consistência entre métodos de persistência de diferentes entidades.

public interface GenericDAO<T> {
    void insert(T entity) throws SQLException;
    List<T> selectAll() throws SQLException;
    T selectById(Long id) throws SQLException;
    void update(T entity) throws SQLException;
    void delete(Long id) throws SQLException;
}
UsuarioDAO.java - Implementando a Interface
public class UsuarioDAO implements GenericDAO<UsuarioModel> {
    private Connection connection;
    
    public UsuarioDAO(Connection connection) {
        this.connection = connection;
    }
    
    @Override
    public void insert(UsuarioModel usuario) throws SQLException {
        String sql = "INSERT INTO usuarios (nome, email) VALUES (?, ?)";
        PreparedStatement stmt = connection.prepareStatement(sql);
        stmt.setString(1, usuario.getNome());
        stmt.setString(2, usuario.getEmail());
        stmt.executeUpdate();
    }
    
    @Override
    public List<UsuarioModel> selectAll() throws SQLException {
        String sql = "SELECT * FROM usuarios";
        PreparedStatement stmt = connection.prepareStatement(sql);
        ResultSet rs = stmt.executeQuery();
        
        List<UsuarioModel> usuarios = new ArrayList<>();
        while (rs.next()) {
            UsuarioModel usuario = new UsuarioModel();
            usuario.setId(rs.getLong("id"));
            usuario.setNome(rs.getString("nome"));
            usuario.setEmail(rs.getString("email"));
            usuarios.add(usuario);
        }
        return usuarios;
    }
    
    @Override
    public UsuarioModel selectById(Long id) throws SQLException {
        String sql = "SELECT * FROM usuarios WHERE id = ?";
        PreparedStatement stmt = connection.prepareStatement(sql);
        stmt.setLong(1, id);
        ResultSet rs = stmt.executeQuery();
        
        if (rs.next()) {
            UsuarioModel usuario = new UsuarioModel();
            usuario.setId(rs.getLong("id"));
            usuario.setNome(rs.getString("nome"));
            usuario.setEmail(rs.getString("email"));
            return usuario;
        }
        return null;
    }
    
    @Override
    public void update(UsuarioModel usuario) throws SQLException {
        String sql = "UPDATE usuarios SET nome = ?, email = ? WHERE id = ?";
        PreparedStatement stmt = connection.prepareStatement(sql);
        stmt.setString(1, usuario.getNome());
        stmt.setString(2, usuario.getEmail());
        stmt.setLong(3, usuario.getId());
        stmt.executeUpdate();
    }
    
    @Override
    public void delete(Long id) throws SQLException {
        String sql = "DELETE FROM usuarios WHERE id = ?";
        PreparedStatement stmt = connection.prepareStatement(sql);
        stmt.setLong(1, id);
        stmt.executeUpdate();
    }
}

Vantagem

Com essa estratégia, todos os DAOs seguem o mesmo padrão. Se você criar um ProdutoDAO, ele também implementará GenericDAO<ProdutoModel> com os mesmos métodos obrigatórios.

Da estrutura DAO ao Spring Boot

Spring Boot lida com persistência através do módulo Spring Data JPA. Ao estender a interface JpaRepository, ganhamos automaticamente todos os métodos CRUD e muito mais, eliminando a necessidade de escrever ou declarar esses métodos nas classes DAO manualmente.

ℹ️Atenção

Essa mágica da interface do Spring funciona por meio de recursos do Java como Proxy e Reflection.

Adicionando o Spring Boot na jogada

Ao usarmos interface UsuarioRepository extends JpaRepository<Usuario, Long>, o Spring cria automaticamente uma implementação concreta em tempo de execução. Esse processo usa as regras de instanciação definida no contêiner do Spring.

Vantagens das interfaces com Spring Boot

DAO Manual

Estrutura tradicional com implementação manual das funções CRUD

Prós
  • Controle total sobre a lógica
Contras
  • Muito código repetido
  • Pouca escalabilidade

Interface com Spring Boot

Uso de JpaRepository para abstrair persistência

Prós
  • Menos código
  • Mais produtivo
  • Menor chance de erro
Contras
  • Menor controle personalizado

Persistência padronizada: Benefícios reais

O uso de interfaces e Spring permite foco na lógica de negócio, padronizando a persistência e entregando melhor performance de desenvolvimento. Além disso, reduz bugs em queries e facilita a escrita de testes automatizados.

Atenção

Ao abraçar interfaces, você acelera o desenvolvimento, reduz código duplicado e adota melhores práticas do ecossistema Java.

Ferramentas úteis na jornada

IntelliJ IDEA

IDE poderosa para desenvolvimento Java

Saiba mais →

Spring Initializr

Gerador de projetos Spring Boot

Saiba mais →

PostgreSQL

Banco de dados relacional usado com JPA

Camadas de abstração e escalabilidade

Com interfaces implementadas corretamente, é possível criar camadas intermediárias como services e facades que se comunicam com os repositórios, mantendo o baixo acoplamento e facilitando a manutenção da aplicação.

Repensando DAOs antigos

Mesmo sistemas legados podem ser refatorados a partir de interfaces. Isso permite criar um novo backend em Spring e fazer migrações parciais com segurança e previsibilidade.

Humanizando o desenvolvedor

Compartilhar histórias despretensiosas, como tentativas frustradas de outras carreiras antes da programação, ajuda a criar conexão. Essa abordagem mostra que por trás do dev existe uma trajetória e aprendizado.

Checklist de Implementação

Criou as classes model seguindo entidades do projeto
Implementou interfaces genéricas para os DAOs
Migrou para Spring Data JPA usando JpaRepository
Testou persistência com classes Repository
Organizou as camadas em estrutura MVC

Domine React e Node com o CrazyStack

Aprenda técnicas avançadas de React com nosso curso completo