Pular para o conteúdo

Lista de Exercícios 002: Singleton

Para cada cenário abaixo, indique se o padrão Singleton é apropriado ou não e justifique em 2–3 frases.

  1. Um serviço de configurações da aplicação que carrega propriedades de um arquivo (application.properties) e é lido por vários módulos de um sistema web.
  2. Um componente responsável por gerenciar conexões HTTP para chamadas a APIs externas, onde diferentes partes do sistema podem precisar de configurações de timeout e autenticação distintas.
  3. Um logger central que registra eventos da aplicação em arquivo/console, usado por dezenas de classes diferentes.
  4. Uma classe que representa o usuário autenticado atual em um sistema web com múltiplos usuários acessando simultaneamente.
  5. Um cache em memória compartilhado entre vários serviços do back-end, que armazena dados frequentemente lidos do banco.

Para cada item, responda:

  • “Faz sentido usar Singleton” ou “Não faz sentido usar Singleton”.
  • Explique rapidamente o porquê (unicidade, escopo, concorrência, testes, etc.).

Exercício 2 – Criando uma analogia para Singleton

Seção intitulada “Exercício 2 – Criando uma analogia para Singleton”

Crie uma analogia própria para explicar o padrão Singleton para alguém que não é da área de TI.

  1. Descreva uma situação do mundo real em que:
    • exista algo que deve ser único,
    • e que seja acessado por várias pessoas/locais diferentes.
  2. Explique por que essa analogia representa bem:
    • a ideia de única instância,
    • e de ponto global de acesso.
  3. Indique também uma limitação da sua analogia (algo que não encaixa perfeitamente com o padrão).

Exercício 3 – Anti‑pattern: Singleton usado de forma errada

Seção intitulada “Exercício 3 – Anti‑pattern: Singleton usado de forma errada”

Considere o código Java abaixo, usado em uma aplicação desktop de vendas:

public class CarrinhoDeComprasSingleton {
private static CarrinhoDeComprasSingleton instancia;
private List<Item> itens = new ArrayList<>();
private CarrinhoDeComprasSingleton() { }
public static CarrinhoDeComprasSingleton getInstancia() {
if (instancia == null) {
instancia = new CarrinhoDeComprasSingleton();
}
return instancia;
}
public void adicionarItem(Item item) {
itens.add(item);
}
public List<Item> getItens() {
return itens;
}
// ...outros métodos de regras de negócio...
}

Em uma versão futura, essa aplicação passa a ser multiusuário (cada cliente loga com sua conta, possivelmente em paralelo).

Responda:

  1. Por que esse uso de Singleton é um problema arquitetural nesse cenário?
  2. Que tipo de bugs ou comportamentos estranhos podem acontecer quando vários usuários utilizarem o sistema ao mesmo tempo?
  3. Sugira outra abordagem de design para o carrinho (sem usar Singleton) e explique, em linhas gerais, como as instâncias deveriam ser gerenciadas.

Exercício 4 – Singleton em um projeto open source real

Seção intitulada “Exercício 4 – Singleton em um projeto open source real”

Acesse o seguinte arquivo em um projeto open source:

Esse arquivo não é exatamente um “Singleton clássico”, mas o Spring usa fortemente a ideia de instâncias únicas gerenciadas por um contêiner (IoC Container), que muitas vezes substituem Singletons manuais.

Responda:

  1. No contexto do Spring, o que significa um bean de escopo singleton (explique com suas palavras)?
  2. Dê um exemplo (do próprio Spring, ou de um projeto que você já viu) de um componente que normalmente é configurado como singleton (por exemplo, DataSource, RestTemplate, ObjectMapper).
  3. Explique qual problema esse “singleton gerenciado pelo framework” resolve em aplicações corporativas (pense em performance, reuso, configuração centralizada).
  4. Comente uma vantagem de deixar o framework gerenciar singletons, em vez de implementar MinhaClasse.getInstancia() manualmente.

Exercício 6 – Implementando um Sistema de Alertas

Seção intitulada “Exercício 6 – Implementando um Sistema de Alertas”

Imagine que você foi contratado para criar um Sistema Central de Alertas de Emergência para diferentes órgãos de segurança:

  • Polícia
  • Bombeiros
  • SAMU

Cada órgão possui seu próprio módulo no sistema, mas todos precisam acessar o mesmo centro de controle para:

  • enviar alertas (por exemplo: acidente, incêndio, assalto),
  • receber mensagens já registradas no sistema (histórico de alertas).

Implemente, em Java, um sistema em que exista apenas um “central de alertas” na aplicação inteira, usando o padrão Singleton.

  1. Crie uma classe CentralDeAlertas que seja um Singleton:

    • Construtor privado.
    • Um método público estático getInstancia() que sempre retorna a mesma instância.
    • Uma estrutura interna (por exemplo, List<String> mensagens) para armazenar os alertas enviados.
    • Métodos, por exemplo:
      • public void enviarAlerta(String orgao, String mensagem) – adiciona uma nova mensagem ao sistema, incluindo o nome do órgão que enviou.
      • public List<String> getAlertas() – retorna a lista de mensagens registradas.
  2. Implemente três classes representando os órgãos:

    • Policia
    • Bombeiros
    • Samu

    Cada uma deve:

    • Obter a instância da CentralDeAlertas via getInstancia() (nunca usando new).
    • Ter um método, por exemplo, enviarAlerta(String mensagem) que encaminha a mensagem para a CentralDeAlertas.
    • Ter um método para listar os alertas registrados na central.
  3. Crie uma classe de teste, por exemplo MainEmergencias, que:

    • Crie objetos de Policia, Bombeiros e Samu.
    • Faça cada órgão enviar pelo menos um alerta (mensagens diferentes).
    • Liste os alertas a partir de pelo menos dois órgãos diferentes e mostre que todos veem o mesmo histórico (com as mensagens de todos).
    • Comprove, se quiser, imprimindo o hashCode() da instância de CentralDeAlertas em partes diferentes do código para mostrar que é sempre o mesmo objeto.
  4. Responda em texto (ou em comentários no código):

    • Por que faz sentido que a CentralDeAlertas seja um Singleton nesse contexto?
    • Que problemas poderiam acontecer se cada órgão tivesse sua própria instância de central (por exemplo, perder mensagens, históricos diferentes, falta de coordenação)?
    • Sua implementação é thread-safe? Se não, o que poderia ser feito para torná-la segura em um cenário com múltiplas threads (por exemplo, vários módulos disparando alertas ao mesmo tempo)?

Opcionalmente, deixe o exercício mais divertido:

  • Inclua tipos de alerta (enum: INCENDIO, ACIDENTE, ROUBO, etc.).
  • Registre também horário dos alertas.
  • Formate a saída para parecer um painel de controle de uma central de emergências.

Exercício 6 – Implementando um Singleton em Java

Seção intitulada “Exercício 6 – Implementando um Singleton em Java”

Implemente, em Java, uma classe ConfiguracaoSistema que representa um conjunto de configurações globais da aplicação (por exemplo: modoDebug, urlApi, timeoutSegundos).

  1. A classe deve ser um Singleton thread-safe, com:
    • construtor privado,
    • um método público estático getInstancia() que sempre retorna a mesma instância,
    • uma implementação que não crie mais de uma instância mesmo em ambiente multithread.
  2. A classe deve possuir, no mínimo:
    • um atributo private boolean modoDebug;
    • um atributo private String urlApi;
    • um atributo private int timeoutSegundos;
    • métodos get e set para cada um desses atributos.
  3. Crie uma classe de teste simples (por exemplo, MainConfiguracao) que:
    • obtenha a instância de ConfiguracaoSistema em dois pontos diferentes do código,
    • altere um atributo em um ponto,
    • e mostre (via System.out.println) que a alteração é visível no outro ponto, comprovando que é a mesma instância.
  4. Opcional: comente no código (ou em texto separado) qual estratégia de thread-safety você escolheu (por exemplo: synchronized, eager initialization, double-checked locking, enum) e por que ela é adequada para esse cenário.