Feature Java: Sealed Classes
Em Java, as Sealed Classes representam um recurso poderoso para modelar domínios específicos e restringir hierarquias de classes de forma a garantir clareza e segurança no manuseio de subclasses conhecidas. Introduzidas inicialmente como uma funcionalidade em preview nas versões 15 e 16 do Java, as Sealed Classes foram oficialmente lançadas na versão 17. Este post visa explorar como as Sealed Classes podem ser usadas para aprimorar a modelagem de domínio, diferenciando-se do uso tradicional de herança focada apenas em reutilização de código.
O que são Sealed Classes?
Em Java, uma Sealed Class é uma classe cuja criação de subclasses é limitada a um conjunto específico de classes conhecidas definidas pelo autor da classe original. Isso é especialmente útil em contextos onde é desejável prever todas as subclasses possíveis, como em bibliotecas gráficas ou aplicações financeiras, para melhor gerenciamento e manutenção do código.
Vantagens das Sealed Classes:
-
Restrição Controlada: Ao utilizar uma Sealed Class, o desenvolvedor pode declarar explicitamente quais classes podem estender a classe principal, evitando a extensão arbitrária e assegurando que apenas subclasses planejadas sejam criadas.
-
Melhor Modelagem de Domínio: Com Sealed Classes, é mais fácil modelar um domínio com precisão, pois o desenvolvedor pode definir claramente as categorias de objetos que são relevantes para o domínio, como diferentes tipos de formas em uma biblioteca gráfica.
-
Clareza e Segurança no Código: Limitar a herança a subclasses conhecidas elimina a necessidade de escrever código defensivo contra subclasses desconhecidas, promovendo maior clareza e segurança.
Como Utilizar Sealed Classes em Java?
Exemplo 1 - Modelagem de Estados de um Pedido
Suponha que você está desenvolvendo um sistema para uma loja online, onde cada pedido pode estar em um de vários estados possíveis, como "Novo", "Pago", "Enviado" e "Cancelado". Utilizar Sealed Classes pode ajudar a representar esses estados de forma segura e clara, garantindo que o tratamento de estados seja abrangente e fácil de manter.
public sealed class OrderState permits New, Paid, Shipped, Cancelled {
// Classe base abstrata para os estados de um pedido
}
public final class NewState extends OrderState {
// Estado específico para um novo pedido
}
public final class PaidState extends OrderState {
// Estado específico para um pedido pago
}
public final class ShippedState extends OrderState {
// Estado específico para um pedido enviado
}
public final class CancelledState extends OrderState {
// Estado específico para um pedido cancelado
}
public void processOrder(OrderState state) {
switch (NewState) {
case New n -> System.out.println("Pedido recebido.");
case PaidState p -> System.out.println("Pedido pago e pronto para envio.");
case ShippedState s -> System.out.println("Pedido enviado ao cliente.");
case CancelledState c -> System.out.println("Pedido cancelado.");
}
}
A classe OrderState
é sealed e limita suas subclasses a NewState
, PaidState
, ShippedState
e CancelledState
, cobrindo todos os estados possíveis de um pedido. Essa abordagem garante que a lógica de processamento de pedidos considere todos os estados definidos, evitando erros de tratamento de estado e facilitando futuras atualizações ou manutenções no sistema de pedidos.
Exemplo 2 - Operações em uma Aplicação de Desenho
Em uma aplicação de desenho, pode haver várias operações que o usuário pode realizar, como desenhar, apagar e selecionar. Modelar essas operações usando Sealed Classes pode ajudar a organizar o código e garantir que todas as operações sejam tratadas de forma consistente.
public sealed class DrawingOperation permits Draw, Erase, Select {
// Classe base para operações de desenho
}
public final class Draw extends DrawingOperation {
private String color;
// Método e propriedades específicas para desenhar
}
public final class Erase extends DrawingOperation {
// Método e propriedades específicas para apagar
}
public final class Select extends DrawingOperation {
// Método e propriedades específicas para selecionar
}
public void executeOperation(DrawingOperation operation) {
if (operation instanceof Draw) {
System.out.println("Desenhando com a cor: " + ((Draw) operation).color);
} else if (operation instanceof Erase) {
System.out.println("Apagando desenho");
} else if (operation instanceof Select) {
System.out.println("Selecionando objeto");
}
}
A classe DrawingOperation
é sealed e permite apenas as subclasses Draw
, Erase
e Select
, cobrindo todas as operações básicas na aplicação de desenho. Isso assegura que cada tipo de operação seja tratado adequadamente no método executeOperation
, facilitando a extensão ou modificação de operações na aplicação sem comprometer a integridade do sistema.
Conclusão
As Sealed Classes são uma ferramenta essencial para quem deseja um controle mais estrito sobre as hierarquias de classes em Java, permitindo uma modelagem de domínio mais clara e precisa. Incorporar Sealed Classes em seus projetos pode trazer benefícios significativos em termos de manutenibilidade e clareza do código.