Os 4 pilares da Programação Orientada a Objetos (encapsulamento, abstração,
herança e polimorfismo) não mudaram, mas o jeito de escrever POO em Java
mudou muito nos últimos anos. Neste artigo, uso um exemplo prático — uma
mini plataforma de streaming de música — para revisar cada pilar e mostrar
como features modernas como record, sealed e switch com pattern
matching tornam o código mais enxuto e mais seguro.
O cenário: uma plataforma de streaming
A ideia é simples: temos Artist, e dois tipos de mídia que podem ser
tocados, Song e MusicVideo, ambos compartilhando comportamento comum
através de uma classe Media.
1. Encapsulamento com record
Antes do Java 16, encapsular um dado imutável como Artist exigia escrever
construtor, getters, equals, hashCode e toString na mão. Com record,
tudo isso vem de graça:
public record Artist(String name, String genre) {}O compilador gera campos private final, getters (name(), genre()) e as
implementações de equals/hashCode/toString. É encapsulamento no seu
estado mais puro: os dados ficam protegidos e só são acessados através dos
métodos gerados.
2. Abstração com interface
Uma interface define o que algo faz, sem se preocupar com como:
interface Streamable {
void stream();
}Qualquer mídia que possa ser transmitida implementa esse contrato.
3. Abstração e encapsulamento na classe abstrata
A classe Media concentra o que é comum a toda mídia (título, artista,
contagem de plays) e usa sealed para restringir quem pode estendê-la:
abstract sealed class Media implements Streamable permits Song, MusicVideo {
private final String title;
private final Artist artist;
private int playCount;
public Media(String title, Artist artist) {
this.title = title;
this.artist = artist;
this.playCount = 0;
}
protected void incrementPlays() {
this.playCount++;
}
public String getTitle() { return title; }
public Artist getArtist() { return artist; }
public int getPlayCount() { return playCount; }
public abstract void displayDetails();
}| Conceito | Onde aparece | Por quê |
|---|---|---|
| Encapsulamento | Campos private final | Protege o estado interno de Media |
| Abstração | abstract void displayDetails() | Define contrato sem implementação |
sealed | permits Song, MusicVideo | Só essas duas classes podem herdar de Media |
O sealed é o que torna a hierarquia fechada e previsível: o compilador
sabe exatamente quais subtipos existem, o que abre caminho para o pattern
matching exaustivo que vem a seguir.
4. Herança
Song e MusicVideo herdam de Media e reaproveitam título, artista e
contador de plays:
final class Song extends Media {
private final boolean hasLyrics;
public Song(String title, Artist artist, boolean hasLyrics) {
super(title, artist);
this.hasLyrics = hasLyrics;
}
@Override
public void stream() {
incrementPlays();
System.out.println("Streaming audio: " + getTitle() + " by " + getArtist().name());
if (hasLyrics) {
System.out.println("-> Displaying synced lyrics on screen...");
}
}
@Override
public void displayDetails() {
System.out.println("Song: " + getTitle() + " | Total Plays: " + getPlayCount());
}
}MusicVideo segue o mesmo princípio, mas guarda a resolução do vídeo em vez
de saber se tem letra sincronizada.
5. Polimorfismo em ação
Uma lista de Media guarda Song e MusicVideo ao mesmo tempo. Em tempo de
execução, Java decide qual stream() chamar:
List<Media> playlist = List.of(track1, track2);
for (Media media : playlist) {
media.stream(); // polimorfismo: cada tipo executa sua própria versão
switch (media) {
case Song s -> System.out.println("[Added " + s.getTitle() + " to Audio Favorites]");
case MusicVideo mv -> System.out.println("[Added " + mv.getTitle() + " to Video Favorites]");
}
}O switch com pattern matching (Java 21) substitui cadeias de instanceof +
cast. E como Media é sealed, o compilador consegue verificar em tempo
de compilação que todos os casos foram tratados — sem precisar de um
default.
Conclusão
Os 4 pilares da POO continuam sendo a base de tudo, mas record, sealed e
pattern matching tiram trabalho repetitivo das nossas mãos e trazem mais
segurança do compilador. O resultado é um código mais curto, mais expressivo
e com menos espaço para erro.
Compartilhar
