From b2b8807560e494b3bfae76e53e135ed99aa75889 Mon Sep 17 00:00:00 2001 From: jrcfxx Date: Sat, 30 May 2026 18:06:59 -0300 Subject: [PATCH] comentarios --- gerenciamento/src/edu/hackaton/Main.java | 208 ++++++++++-------- .../src/edu/hackaton/model/Apresentacao.java | 15 +- .../src/edu/hackaton/model/Banca.java | 21 ++ .../src/edu/hackaton/model/Equipe.java | 10 + .../src/edu/hackaton/model/Estudante.java | 6 +- .../src/edu/hackaton/model/IAvaliavel.java | 6 + .../src/edu/hackaton/model/Jurado.java | 6 +- .../src/edu/hackaton/model/Pessoa.java | 8 +- .../src/edu/hackaton/model/Profissional.java | 6 +- .../src/edu/hackaton/model/Projeto.java | 10 + .../src/edu/hackaton/model/Sala.java | 3 + .../hackaton/model/instituicao/Empresa.java | 4 + .../model/instituicao/Instituicao.java | 6 +- .../model/instituicao/Universidade.java | 7 +- .../hackaton/repository/Apresentacoes.java | 20 +- .../src/edu/hackaton/repository/Equipes.java | 17 +- 16 files changed, 249 insertions(+), 104 deletions(-) diff --git a/gerenciamento/src/edu/hackaton/Main.java b/gerenciamento/src/edu/hackaton/Main.java index 65fa11c..bcf65d8 100644 --- a/gerenciamento/src/edu/hackaton/Main.java +++ b/gerenciamento/src/edu/hackaton/Main.java @@ -8,100 +8,122 @@ import java.time.LocalDateTime; +/* + * REVIEW [Arquitetura]: Inconsistência estrutural - arquivos em edu/hackaton/, mas package br.edu.hackathon. + * Alinhar diretório ao pacote (convenção Java) ou atualizar README. + */ public class Main { - public static void main(String[] args) { - Universidade u1 = new Universidade("UFABC"); - Universidade u2 = new Universidade("USP"); - Empresa emp1 = new Empresa("Google"); - Empresa emp2 = new Empresa("Meta"); + // REVIEW [Arquitetura / SRP]: main concentra bootstrap, avaliação, persistência + // e relatório (God Method). + // Sugestão: extrair GerenciadorHackathon ou HackathonBootstrap; main só chama o + // serviço. + public static void main(String[] args) { + + Universidade u1 = new Universidade("UFABC"); + Universidade u2 = new Universidade("USP"); + Empresa emp1 = new Empresa("Google"); + Empresa emp2 = new Empresa("Meta"); + + Profissional orientador1 = new Profissional("Carlos", emp1); + Profissional orientador2 = new Profissional("Ana", emp2); + + Equipe equipe1 = new Equipe("Equipe Inovação"); + // REVIEW [Regra de negócio]: limite de 5 membros está só no loop; + // Equipe.adicionarMembro não valida. + for (int i = 1; i <= 5; i++) { + equipe1.adicionarMembro(new Estudante("Aluno" + i, u1)); + } + Projeto projeto1 = new Projeto("Sistema IoT", orientador1, equipe1); + + Equipe equipe2 = new Equipe("Equipe Tecnologia"); + for (int i = 6; i <= 10; i++) { + equipe2.adicionarMembro(new Estudante("Aluno" + i, u2)); + } + Projeto projeto2 = new Projeto("App Mobile", orientador2, equipe2); + + Equipes equipesRepo = Equipes.getInstance(); + equipesRepo.adicionarEquipe(equipe1); + equipesRepo.adicionarEquipe(equipe2); + + Banca banca1 = new Banca(projeto1); + banca1.adicionarNota(new Jurado("Jurado 1", emp1), 8); + banca1.adicionarNota(new Jurado("Jurado 2", emp1), 7); + banca1.adicionarNota(new Jurado("Jurado 3", emp2), 9); + banca1.adicionarNota(new Jurado("Jurado 4", emp2), 8); + + Banca banca2 = new Banca(projeto2); + banca2.adicionarNota(new Jurado("Jurado 5", emp2), 6); + banca2.adicionarNota(new Jurado("Jurado 6", emp1), 3); + banca2.adicionarNota(new Jurado("Jurado 7", emp1), 6); + banca2.adicionarNota(new Jurado("Jurado 8", emp2), 5); + + Apresentacao ap1 = new Apresentacao( + projeto1, + banca1, + new Sala("Auditório Principal"), + LocalDateTime.now()); + ap1.avaliar(); + + Apresentacao ap2 = new Apresentacao( + projeto2, + banca2, + new Sala("Sala 205"), + LocalDateTime.now()); + ap2.avaliar(); + + /* + * REVIEW [Fluxo / Repository]: apresentações avaliadas antes de ir ao + * repositório; + * relatório usa só Equipes - Apresentacoes fica subutilizado. Registrar antes + * ou listar por apresentacoesRepo. + */ + Apresentacoes apresentacoesRepo = Apresentacoes.getInstance(); + apresentacoesRepo.adicionar(ap1); + apresentacoesRepo.adicionar(ap2); + + System.out.println("===================================="); + System.out.println("PROJETOS APROVADOS (NOTA >= 7)"); + System.out.println("===================================="); + + // REVIEW [Code smell]: número mágico 7 - extrair NOTA_MINIMA_APROVACAO ou + // PoliticaAvaliacao. + equipesRepo.getEquipes().stream() + .filter(e -> e.getProjeto().getNotaFinal() >= 7) + .forEach(e -> { + Projeto p = e.getProjeto(); + // REVIEW [Lei de Demeter]: cadeia e.getProjeto().getOrientador() - preferir + // p.resumoParaRelatorio() ou DTO. + System.out.printf( + "» %s - Nota: %d%n" + + " Orientador: %s%n" + + " Equipe: %s (%d membros)%n%n", + p.getNome(), + p.getNotaFinal(), + p.getOrientador().getNome(), + e.getNome(), + e.getMembros().size()); + }); + + System.out.println("===================================="); + System.out.println("PROJETOS REPROVADOS (NOTA < 7)"); + System.out.println("===================================="); + + /* + * REVIEW [DRY / Refatoração]: dois streams quase iguais - usar + * Collectors.partitioningBy + * ou classe RelatorioConsole com um único ponto de iteração. + */ + equipesRepo.getEquipes().stream() + .filter(e -> e.getProjeto().getNotaFinal() < 7) + .forEach(e -> { + Projeto p = e.getProjeto(); + System.out.printf( + "» %s - Nota: %d%n" + + " Motivo: Nota insuficiente%n%n", + p.getNome(), + p.getNotaFinal()); + }); - Profissional orientador1 = new Profissional("Carlos", emp1); - Profissional orientador2 = new Profissional("Ana", emp2); - - Equipe equipe1 = new Equipe("Equipe Inovação"); - for (int i = 1; i <= 5; i++) { - equipe1.adicionarMembro(new Estudante("Aluno" + i, u1)); - } - Projeto projeto1 = new Projeto("Sistema IoT", orientador1, equipe1); - - Equipe equipe2 = new Equipe("Equipe Tecnologia"); - for (int i = 6; i <= 10; i++) { - equipe2.adicionarMembro(new Estudante("Aluno" + i, u2)); } - Projeto projeto2 = new Projeto("App Mobile", orientador2, equipe2); - - Equipes equipesRepo = Equipes.getInstance(); - equipesRepo.adicionarEquipe(equipe1); - equipesRepo.adicionarEquipe(equipe2); - - Banca banca1 = new Banca(projeto1); - banca1.adicionarNota(new Jurado("Jurado 1", emp1), 8); - banca1.adicionarNota(new Jurado("Jurado 2", emp1), 7); - banca1.adicionarNota(new Jurado("Jurado 3", emp2), 9); - banca1.adicionarNota(new Jurado("Jurado 4", emp2), 8); - - Banca banca2 = new Banca(projeto2); - banca2.adicionarNota(new Jurado("Jurado 5", emp2), 6); - banca2.adicionarNota(new Jurado("Jurado 6", emp1), 3); - banca2.adicionarNota(new Jurado("Jurado 7", emp1), 6); - banca2.adicionarNota(new Jurado("Jurado 8", emp2), 5); - - Apresentacao ap1 = new Apresentacao( - projeto1, - banca1, - new Sala("Auditório Principal"), - LocalDateTime.now() - ); - ap1.avaliar(); - - Apresentacao ap2 = new Apresentacao( - projeto2, - banca2, - new Sala("Sala 205"), - LocalDateTime.now() - ); - ap2.avaliar(); - - Apresentacoes apresentacoesRepo = Apresentacoes.getInstance(); - apresentacoesRepo.adicionar(ap1); - apresentacoesRepo.adicionar(ap2); - - System.out.println("===================================="); - System.out.println("PROJETOS APROVADOS (NOTA >= 7)"); - System.out.println("===================================="); - - equipesRepo.getEquipes().stream() - .filter(e -> e.getProjeto().getNotaFinal() >= 7) - .forEach(e -> { - Projeto p = e.getProjeto(); - System.out.printf( - "» %s - Nota: %d%n" + - " Orientador: %s%n" + - " Equipe: %s (%d membros)%n%n", - p.getNome(), - p.getNotaFinal(), - p.getOrientador().getNome(), - e.getNome(), - e.getMembros().size() - ); - }); - - System.out.println("===================================="); - System.out.println("PROJETOS REPROVADOS (NOTA < 7)"); - System.out.println("===================================="); - - equipesRepo.getEquipes().stream() - .filter(e -> e.getProjeto().getNotaFinal() < 7) - .forEach(e -> { - Projeto p = e.getProjeto(); - System.out.printf( - "» %s - Nota: %d%n" + - " Motivo: Nota insuficiente%n%n", - p.getNome(), - p.getNotaFinal() - ); - }); - - } -} \ No newline at end of file +} diff --git a/gerenciamento/src/edu/hackaton/model/Apresentacao.java b/gerenciamento/src/edu/hackaton/model/Apresentacao.java index 47a5997..9e9a9e6 100644 --- a/gerenciamento/src/edu/hackaton/model/Apresentacao.java +++ b/gerenciamento/src/edu/hackaton/model/Apresentacao.java @@ -4,10 +4,19 @@ public class Apresentacao { private Projeto projeto; + + /* + * REVIEW [Nomenclatura / DIP]: campo "avaliavel" sugere interface, mas tipo é Banca (concreto). + * Renomear para banca ou declarar como IAvaliavel para polimorfismo (Strategy). + */ private Banca avaliavel; private Sala sala; private LocalDateTime horario; + /* + * REVIEW [Validação inconsistente]: Projeto, Banca e Sala validam nulos; aqui não. + * Usar Objects.requireNonNull em todos os parâmetros do construtor. + */ public Apresentacao(Projeto projeto, Banca banca, Sala sala, LocalDateTime horario) { this.projeto = projeto; this.avaliavel = banca; @@ -15,8 +24,12 @@ public Apresentacao(Projeto projeto, Banca banca, Sala sala, LocalDateTime horar this.horario = horario; } + /* + * REVIEW [Responsabilidade]: orquestra avaliação corretamente, mas poderia emitir evento + * ou delegar a um AvaliacaoService na camada de aplicação (separação domínio vs orquestração). + */ public void avaliar() { int media = avaliavel.calcularNotaFinal(); projeto.setNotaFinal(media); } -} \ No newline at end of file +} diff --git a/gerenciamento/src/edu/hackaton/model/Banca.java b/gerenciamento/src/edu/hackaton/model/Banca.java index 1b768cb..fda056a 100644 --- a/gerenciamento/src/edu/hackaton/model/Banca.java +++ b/gerenciamento/src/edu/hackaton/model/Banca.java @@ -3,8 +3,19 @@ import java.util.HashMap; import java.util.Map; +/* + * REVIEW [Padrão Strategy / DIP]: implementa IAvaliavel, mas Apresentacao usa tipo concreto Banca. + * Campo em Apresentacao deveria ser IAvaliavel para trocar estratégia de avaliação sem alterar Apresentacao. + */ public class Banca implements IAvaliavel { private Projeto projetoAvaliado; + + /* + * REVIEW [Design HashMap]: chave Jurado sem equals/hashCode em Pessoa - compara + * por referência. + * Implementar equals/hashCode em Pessoa ou usar identificador (String) como + * chave. + */ private Map jurados = new HashMap<>(); public Banca(Projeto projetoAvaliado) { @@ -31,6 +42,12 @@ public int calcularNotaFinal() { return 0; } int soma = jurados.values().stream().mapToInt(Integer::intValue).sum(); + /* + * REVIEW [Bug / Regra de negócio]: divisão inteira trunca a média (ex.: 7,75 + * vira 7). + * Usar Math.round((double) soma / jurados.size()) ou Strategy + * EstrategiaCalculoNota. + */ return (int) soma / jurados.size(); } @@ -38,6 +55,10 @@ public Projeto getProjetoAvaliado() { return projetoAvaliado; } + /* + * REVIEW [Encapsulamento]: retorna Map mutável interno - expõe estado. + * Retornar Collections.unmodifiableMap(jurados) ou cópia defensiva. + */ public Map getJurados() { return jurados; } diff --git a/gerenciamento/src/edu/hackaton/model/Equipe.java b/gerenciamento/src/edu/hackaton/model/Equipe.java index 7493df9..a088072 100644 --- a/gerenciamento/src/edu/hackaton/model/Equipe.java +++ b/gerenciamento/src/edu/hackaton/model/Equipe.java @@ -13,10 +13,20 @@ public Equipe(String nome) { this.membros = new ArrayList<>(); } + /* + * REVIEW [Regra de negócio]: sem limite de membros no domínio (enunciado sugere + * equipes fixas). + * if (membros.size() >= 5) throw new IllegalStateException("Equipe cheia"); + */ public void adicionarMembro(Estudante estudante) { membros.add(estudante); } + /* + * REVIEW [Encapsulamento]: retorna ArrayList mutável - caller pode alterar + * lista interna. + * return Collections.unmodifiableList(membros); + */ public List getMembros() { return membros; } diff --git a/gerenciamento/src/edu/hackaton/model/Estudante.java b/gerenciamento/src/edu/hackaton/model/Estudante.java index 42cfc9e..ec9a63a 100644 --- a/gerenciamento/src/edu/hackaton/model/Estudante.java +++ b/gerenciamento/src/edu/hackaton/model/Estudante.java @@ -2,8 +2,12 @@ import br.edu.hackathon.model.instituicao.Instituicao; +/* + * REVIEW [Subclasse vazia]: marker subclass sem comportamento próprio. + * Se não houver regras específicas de estudante, considerar enum Papel na hierarquia ou composição. + */ public class Estudante extends Pessoa { public Estudante(String nome, Instituicao instituicao) { super(nome, instituicao); } -} \ No newline at end of file +} diff --git a/gerenciamento/src/edu/hackaton/model/IAvaliavel.java b/gerenciamento/src/edu/hackaton/model/IAvaliavel.java index 67045ed..30b74dd 100644 --- a/gerenciamento/src/edu/hackaton/model/IAvaliavel.java +++ b/gerenciamento/src/edu/hackaton/model/IAvaliavel.java @@ -1,5 +1,11 @@ package br.edu.hackathon.model; +/* + * REVIEW [Convenção Java]: prefixo "I" em interfaces é estilo C#; em Java o idioma é Avaliavel. + * + * REVIEW [Padrão Strategy]: contrato adequado para diferentes formas de avaliação (banca presencial, remota, simulada). + * Banca é uma implementação; outras podem calcular média, mediana ou notas ponderadas. + */ public interface IAvaliavel { void adicionarNota(Jurado jurado, int nota); int calcularNotaFinal(); diff --git a/gerenciamento/src/edu/hackaton/model/Jurado.java b/gerenciamento/src/edu/hackaton/model/Jurado.java index 33dd0d6..7933d16 100644 --- a/gerenciamento/src/edu/hackaton/model/Jurado.java +++ b/gerenciamento/src/edu/hackaton/model/Jurado.java @@ -2,8 +2,12 @@ import br.edu.hackathon.model.instituicao.Instituicao; +/* + * REVIEW [Herança / marker subclass]: Jurado só repassa construtor - sem comportamento extra. + * Alternativa: Profissional com enum TipoProfissional { ORIENTADOR, JURADO } (Replace Type Code with Enum). + */ public class Jurado extends Profissional { public Jurado(String nome, Instituicao instituicao) { super(nome, instituicao); } -} \ No newline at end of file +} diff --git a/gerenciamento/src/edu/hackaton/model/Pessoa.java b/gerenciamento/src/edu/hackaton/model/Pessoa.java index a95aeae..ff885f0 100644 --- a/gerenciamento/src/edu/hackaton/model/Pessoa.java +++ b/gerenciamento/src/edu/hackaton/model/Pessoa.java @@ -2,6 +2,12 @@ import br.edu.hackathon.model.instituicao.Instituicao; +/* + * REVIEW [Modelo anêmico / hierarquia rasa]: Pessoa só armazena dados; subclasses não diferenciam comportamento. + * Opções: (1) métodos polimórficos (papelNoHackathon()); (2) uma classe Pessoa + enum Papel { ESTUDANTE, ORIENTADOR, JURADO }. + * + * REVIEW [equals/hashCode]: ausentes - impacta HashMap em Banca. + */ public abstract class Pessoa { private String nome; private Instituicao instituicao; @@ -18,4 +24,4 @@ public String getNome() { public Instituicao getInstituicao() { return instituicao; } -} \ No newline at end of file +} diff --git a/gerenciamento/src/edu/hackaton/model/Profissional.java b/gerenciamento/src/edu/hackaton/model/Profissional.java index 4f6efa0..82c0515 100644 --- a/gerenciamento/src/edu/hackaton/model/Profissional.java +++ b/gerenciamento/src/edu/hackaton/model/Profissional.java @@ -2,8 +2,12 @@ import br.edu.hackathon.model.instituicao.Instituicao; +/* + * REVIEW [Domínio]: orientador é Profissional vinculado a Empresa - coerente com o modelo. + * Jurado extends Profissional: avaliar se jurado sempre é "profissional" no mesmo sentido (pode ser só papel). + */ public class Profissional extends Pessoa { public Profissional(String nome, Instituicao instituicao) { super(nome, instituicao); } -} \ No newline at end of file +} diff --git a/gerenciamento/src/edu/hackaton/model/Projeto.java b/gerenciamento/src/edu/hackaton/model/Projeto.java index c5e8dd8..7be3e3e 100644 --- a/gerenciamento/src/edu/hackaton/model/Projeto.java +++ b/gerenciamento/src/edu/hackaton/model/Projeto.java @@ -1,5 +1,9 @@ package br.edu.hackathon.model; +/* + * REVIEW [DDD / Aggregate Root]: Projeto e Equipe têm referência circular (setProjeto no construtor). + * Definir uma raiz de agregado: ou Equipe associa Projeto via factory, ou Projeto só referencia Equipe sem setter reverso automático. + */ public class Projeto { private String nome; private Profissional orientador; @@ -13,6 +17,12 @@ public Projeto(String nome, Profissional orientador, Equipe equipe) { this.nome = nome; this.orientador = orientador; this.equipe = equipe; + /* + * REVIEW [Code smell - sentinel value]: -1 significa "não avaliado"; frágil em + * filtros (Main >= 7). + * Preferir OptionalInt, enum StatusProjeto { PENDENTE, AVALIADO } ou boolean + * avaliado. + */ this.notaFinal = -1; equipe.setProjeto(this); } diff --git a/gerenciamento/src/edu/hackaton/model/Sala.java b/gerenciamento/src/edu/hackaton/model/Sala.java index 5d26869..2d99fc6 100644 --- a/gerenciamento/src/edu/hackaton/model/Sala.java +++ b/gerenciamento/src/edu/hackaton/model/Sala.java @@ -1,5 +1,8 @@ package br.edu.hackathon.model; +/* + * REVIEW [Boa prática]: validação de nome no construtor - padrão a replicar em Instituicao e Pessoa. + */ public class Sala { private String nome; diff --git a/gerenciamento/src/edu/hackaton/model/instituicao/Empresa.java b/gerenciamento/src/edu/hackaton/model/instituicao/Empresa.java index e239536..b74b426 100644 --- a/gerenciamento/src/edu/hackaton/model/instituicao/Empresa.java +++ b/gerenciamento/src/edu/hackaton/model/instituicao/Empresa.java @@ -1,5 +1,9 @@ package br.edu.hackathon.model.instituicao; +/* + * REVIEW [Tipo de domínio]: Empresa como Instituicao permite jurados/orientadores de empresas parceiras - bom modelagem. + * Evolução: getSetor(), validar CNPJ; Strategy de patrocínio só para Empresa. + */ public class Empresa extends Instituicao { public Empresa(String nome) { super(nome); diff --git a/gerenciamento/src/edu/hackaton/model/instituicao/Instituicao.java b/gerenciamento/src/edu/hackaton/model/instituicao/Instituicao.java index b79c1ac..eed36f3 100644 --- a/gerenciamento/src/edu/hackaton/model/instituicao/Instituicao.java +++ b/gerenciamento/src/edu/hackaton/model/instituicao/Instituicao.java @@ -1,5 +1,9 @@ package br.edu.hackathon.model.instituicao; +/* + * REVIEW [Validação inconsistente]: Sala rejeita nome null/vazio; Instituicao aceita qualquer String. + * Extrair EntidadeNomeada com validação comum ou Objects.requireNonNull + isBlank no construtor. + */ public abstract class Instituicao { private String nome; @@ -10,4 +14,4 @@ public Instituicao(String nome) { public String getNome() { return nome; } -} \ No newline at end of file +} diff --git a/gerenciamento/src/edu/hackaton/model/instituicao/Universidade.java b/gerenciamento/src/edu/hackaton/model/instituicao/Universidade.java index 1bc2775..cc3649c 100644 --- a/gerenciamento/src/edu/hackaton/model/instituicao/Universidade.java +++ b/gerenciamento/src/edu/hackaton/model/instituicao/Universidade.java @@ -1,7 +1,12 @@ package br.edu.hackathon.model.instituicao; +/* + * REVIEW [Polimorfismo futuro]: subclasse só delega super(nome) - sem distinção comportamental. + * Ex.: getSigla(), isPublica(); ou Factory Method Instituicao.criarUniversidade(nome). + * Útil para regras: estudante vinculado a Universidade, patrocínio via Empresa. + */ public class Universidade extends Instituicao { public Universidade(String nome) { super(nome); } -} \ No newline at end of file +} diff --git a/gerenciamento/src/edu/hackaton/repository/Apresentacoes.java b/gerenciamento/src/edu/hackaton/repository/Apresentacoes.java index f5dabcd..8c91a62 100644 --- a/gerenciamento/src/edu/hackaton/repository/Apresentacoes.java +++ b/gerenciamento/src/edu/hackaton/repository/Apresentacoes.java @@ -5,11 +5,20 @@ import java.util.ArrayList; import java.util.List; +/* + * REVIEW [Padrão Singleton]: README cita Singleton, mas thread-safety difere de Equipes. + * getInstance() sem synchronized - risco de duas instâncias em ambiente multithread. + * Alinhar com Equipes ou usar enum singleton / holder idiomático. + * + * REVIEW [Arquitetura / Testabilidade]: Singleton global dificulta testes isolados. + * Alternativa: interface ApresentacaoRepository + injeção de dependência (DIP). + */ public class Apresentacoes { private static Apresentacoes instance; private List apresentacoes = new ArrayList<>(); - private Apresentacoes() {} + private Apresentacoes() { + } public static Apresentacoes getInstance() { if (instance == null) { @@ -19,10 +28,17 @@ public static Apresentacoes getInstance() { } public void adicionar(Apresentacao apresentacao) { + // REVIEW [Validação]: validar null e duplicatas (mesmo projeto/horário) na + // borda do repositório. apresentacoes.add(apresentacao); } + /* + * REVIEW [Encapsulamento - inconsistência com Equipes]: devolve lista mutável + * interna. + * Equipes.getEquipes() usa unmodifiableList; aqui deveria ser o mesmo contrato. + */ public List listar() { return apresentacoes; } -} \ No newline at end of file +} diff --git a/gerenciamento/src/edu/hackaton/repository/Equipes.java b/gerenciamento/src/edu/hackaton/repository/Equipes.java index 5e91859..0c19723 100644 --- a/gerenciamento/src/edu/hackaton/repository/Equipes.java +++ b/gerenciamento/src/edu/hackaton/repository/Equipes.java @@ -3,11 +3,16 @@ import br.edu.hackathon.model.Equipe; import java.util.*; +/* + * REVIEW [Padrão Singleton]: implementação com synchronized - correta para lazy init multithread. + * Padronizar Apresentacoes da mesma forma ou migrar para enum INSTANCE. + */ public class Equipes { private static Equipes instance; private List equipes = new ArrayList<>(); - private Equipes() {} + private Equipes() { + } public static synchronized Equipes getInstance() { if (instance == null) { @@ -16,11 +21,19 @@ public static synchronized Equipes getInstance() { return instance; } + /* + * REVIEW [Validação de domínio]: não valida equipe null, duplicata nem equipe + * sem projeto vinculado. + * Objects.requireNonNull(equipe); opcional Specification para regras de + * inclusão. + */ public void adicionarEquipe(Equipe equipe) { equipes.add(equipe); } + // REVIEW [Boa prática]: retorno imutável - padrão a replicar em + // Apresentacoes.listar(). public List getEquipes() { return Collections.unmodifiableList(equipes); } -} \ No newline at end of file +}