Sistema de Pedidos de Bar — Exercício Prático
Implemente a classe App conforme as instruções abaixo.

Objetivo

Implementar a classe App que controla o fluxo do sistema, exibindo menus, manipulando cardápio e pedidos, e utilizando a classe EntradaSaida para entrada e saída de dados via console.

Classes Fornecidas

ConfigBar.java
public class ConfigBar {
    public static final double TAXA_SERVICO = 0.10;
    public static final double DESCONTO_HAPPY_HOUR = 0.15;
    private static boolean happyHourAtivo = false;

    public static void ativarHappyHour(boolean ativo) { happyHourAtivo = ativo; }
    public static boolean isHappyHourAtivo() { return happyHourAtivo; }
    public static double aplicarDescontoHappyHour(double valor) {
        return happyHourAtivo ? valor * (1 - DESCONTO_HAPPY_HOUR) : valor;
    }
}
ItemCardapio.java
public class ItemCardapio {
    private final String codigo;
    private final String nome;
    private final double preco;
    public ItemCardapio(String codigo, String nome, double preco) {
        if (codigo == null || codigo.isBlank()) throw new IllegalArgumentException("Código inválido");
        if (nome == null || nome.isBlank()) throw new IllegalArgumentException("Nome inválido");
        if (preco < 0) throw new IllegalArgumentException("Preço inválido");
        this.codigo = codigo; this.nome = nome; this.preco = preco;
    }
    public String getCodigo() { return codigo; }
    public String getNome() { return nome; }
    public double getPreco() { return preco; }
}
ItemPedido.java
public class ItemPedido {
    private final ItemCardapio item;
    private int quantidade;
    public ItemPedido(ItemCardapio item, int quantidade) {
        if (item == null) throw new IllegalArgumentException("Item nulo");
        if (quantidade <= 0) throw new IllegalArgumentException("Quantidade inválida");
        this.item = item; this.quantidade = quantidade;
    }
    public double subtotalBruto() { return item.getPreco() * quantidade; }
    public double subtotalComHappyHour() { return ConfigBar.aplicarDescontoHappyHour(subtotalBruto()); }
    public ItemCardapio getItem() { return item; }
    public int getQuantidade() { return quantidade; }
}
Pedido.java
import java.util.ArrayList;
import java.util.List;

public class Pedido {
    // Sequência global para numeração de pedidos (compartilhada)
    private static int proximoNumero = 1;

    // Atributos imutáveis após a criação
    private final int numero;
    private final long criadoEmEpochMillis;

    // Itens que compõem o pedido
    private final List itens = new ArrayList<>();

    public Pedido() {
        this.numero = proximoNumero++;                 // gera número único sequencial
        this.criadoEmEpochMillis = System.currentTimeMillis(); // registra o instante de criação
    }

    public int getNumero() { return numero; }

    public long getCriadoEmEpochMillis() { return criadoEmEpochMillis; }

    /**
     * Retorna uma cópia da lista de itens (defensiva),
     * para evitar que código externo modifique a lista interna.
     */
    public List getItens() {
        return new ArrayList(itens);
    }

    /** Adiciona um item de cardápio ao pedido com a quantidade informada. */
    public void adicionar(ItemCardapio item, int quantidade) {
        itens.add(new ItemPedido(item, quantidade));
    }

    /** Soma todos os itens SEM desconto de Happy Hour. */
    public double totalBruto() {
        double soma = 0.0;
        for (int i = 0; i < itens.size(); i++) {
            ItemPedido ip = itens.get(i);
            soma += ip.subtotalBruto();
        }
        return soma;
    }

    /** Soma todos os itens COM desconto de Happy Hour (se estiver ativo). */
    public double totalComHappyHour() {
        double soma = 0.0;
        for (int i = 0; i < itens.size(); i++) {
            ItemPedido ip = itens.get(i);
            soma += ip.subtotalComHappyHour();
        }
        return soma;
    }

    /** Aplica taxa de serviço (definida em ConfigBar) sobre o total com Happy Hour. */
    public double totalFinalComServico() {
        double base = totalComHappyHour();
        return base + (base * ConfigBar.TAXA_SERVICO);
    }

    /** Gera um texto com o resumo do pedido. */
    public String resumo() {
        StringBuilder sb = new StringBuilder();
        sb.append("Pedido #").append(numero).append("\n");
        sb.append("Happy Hour: ").append(ConfigBar.isHappyHourAtivo() ? "ATIVO" : "inativo").append("\n");

        for (int i = 0; i < itens.size(); i++) {
            ItemPedido ip = itens.get(i);
            sb.append("- ")
              .append(ip.getItem().getNome())
              .append(" x").append(ip.getQuantidade())
              .append(" -> R$ ")
              .append(String.format("%.2f", ip.subtotalComHappyHour()))
              .append("\n");
        }

        sb.append("Total (bruto): R$ ").append(String.format("%.2f", totalBruto())).append("\n");
        sb.append("Total (c/ HH): R$ ").append(String.format("%.2f", totalComHappyHour())).append("\n");
        sb.append("Total (c/ serviço ").append((int)(ConfigBar.TAXA_SERVICO * 100)).append("%): R$ ")
          .append(String.format("%.2f", totalFinalComServico())).append("\n");

        return sb.toString();
    }
}
EntradaSaida.java
import java.util.*;
import java.util.function.Function;

public class EntradaSaida {
    private final Scanner sc = new Scanner(System.in);

    // -------- Utilidades de I/O --------
    public void limparTelaLeve() {
        System.out.print("\033[H\033[2J");
        System.out.flush();
    }

    public void pause() {
        System.out.print("\nPressione ENTER para continuar...");
        sc.nextLine();
    }

    public int lerInt(String prompt) {
        while (true) {
            System.out.print(prompt);
            String s = sc.nextLine().trim();
            try { return Integer.parseInt(s); }
            catch (NumberFormatException e) {
                System.out.println("Digite um número inteiro válido.");
            }
        }
    }

    public double lerDouble(String prompt) {
        while (true) {
            System.out.print(prompt);
            String s = sc.nextLine().replace(",", ".").trim();
            try { return Double.parseDouble(s); }
            catch (NumberFormatException e) {
                System.out.println("Digite um número válido (ex.: 12.50).");
            }
        }
    }

    public String lerLinha(String prompt) {
        System.out.print(prompt);
        return sc.nextLine();
    }

    // -------- Cabeçalho e Menu --------
    public void mostrarCabecalho(boolean happyHourAtivo, double taxaServico, double descontoHH) {
        System.out.println("===============================================");
        System.out.println("        SISTEMA DE PEDIDOS - BAR/ARENA");
        System.out.println("===============================================");
        System.out.println("Happy Hour: " + (happyHourAtivo ? ("ATIVO (" + (int)(descontoHH*100) + "% desc.)")
                                                     : "inativo"));
        System.out.println("Taxa de serviço: " + (int)(taxaServico*100) + "%");
        System.out.println();
    }

    public void mostrarMenuPrincipal() {
        System.out.println("1) Listar cardápio");
        System.out.println("2) Cadastrar item no cardápio");
        System.out.println("3) Ativar/Desativar Happy Hour (global)");
        System.out.println("4) Criar novo pedido");
        System.out.println("5) Adicionar item a um pedido");
        System.out.println("6) Listar pedidos existentes");
        System.out.println("7) Mostrar resumo de um pedido");
        System.out.println("8) Finalizar pedido (exibir totais)");
        System.out.println("9) Sair");
        System.out.println();
    }

    // -------- Telas de Cardápio --------
    public void mostrarCardapio(Map cardapio) {
        System.out.println("\n--- CARDÁPIO ---");
        if (cardapio.isEmpty()) {
            System.out.println("Nenhum item cadastrado.");
            return;
        }
        cardapio.values().forEach(item ->
            System.out.printf("%s | %-25s | R$ %.2f%n",
                    item.getCodigo(), item.getNome(), item.getPreco())
        );
    }

    public void mostrarCardapioCompacto(Map cardapio) {
        System.out.println("\n--- CARDÁPIO (compacto) ---");
        if (cardapio.isEmpty()) {
            System.out.println("Nenhum item cadastrado.");
            return;
        }
        cardapio.values().forEach(item ->
            System.out.printf("%s - %s (R$ %.2f)%n",
                    item.getCodigo(), item.getNome(), item.getPreco())
        );
    }

    /**
     * Solicita os dados de um novo Item de Cardápio e devolve o objeto pronto.
     * Valida código único via função existsCode.apply(cod).
     */
    public ItemCardapio promptNovoItemCardapio(Function existsCode) {
        System.out.println("\n--- CADASTRAR ITEM ---");
        String codigo;
        while (true) {
            codigo = lerLinha("Código (ex.: B001): ").toUpperCase(Locale.ROOT).trim();
            if (codigo.isEmpty()) {
                System.out.println("Código não pode ser vazio.");
                continue;
            }
            if (existsCode.apply(codigo)) {
                System.out.println("Já existe item com esse código.");
                continue;
            }
            break;
        }
        String nome = lerLinha("Nome: ").trim();
        double preco = lerDouble("Preço (ex.: 12.50): ");
        return new ItemCardapio(codigo, nome, preco);
    }

    // -------- Telas de Happy Hour --------
    public boolean promptAlternarHappyHour(boolean estadoAtual) {
        System.out.println("\n--- HAPPY HOUR ---");
        System.out.println("Estado atual: " + (estadoAtual ? "ATIVO" : "inativo"));
        String resp = lerLinha("Deseja alternar? (s/n): ").trim().toLowerCase(Locale.ROOT);
        if (resp.startsWith("s")) return !estadoAtual;
        return estadoAtual;
    }

    // -------- Telas de Pedido --------
    public int promptNumeroPedido() {
        return lerInt("Número do pedido: ");
    }

    public String promptCodigoItem() {
        return lerLinha("Código do item: ").toUpperCase(Locale.ROOT).trim();
    }

    public int promptQuantidade() {
        return lerInt("Quantidade: ");
    }

    public void listarPedidos(Map pedidos) {
        System.out.println("\n--- LISTA DE PEDIDOS ---");
        if (pedidos.isEmpty()) {
            System.out.println("Nenhum pedido criado.");
            return;
        }
        pedidos.values().forEach(p ->
            System.out.printf("Pedido #%d | Itens: %d | Total c/ HH: R$ %.2f%n",
                    p.getNumero(), p.getItens().size(), p.totalComHappyHour())
        );
    }

    public void mostrarResumoPedido(Pedido p) {
        System.out.println();
        System.out.println(p.resumo());
    }

    public void mostrarTotaisPedido(Pedido p, double taxaServico) {
        double bruto = p.totalBruto();
        double comHH = p.totalComHappyHour();
        double finalComServico = p.totalFinalComServico();
        System.out.println("\nResumo rápido:");
        System.out.printf("Total bruto: R$ %.2f%n", bruto);
        System.out.printf("Total com Happy Hour: R$ %.2f%n", comHH);
        System.out.printf("Total final com serviço (%d%%): R$ %.2f%n",
                (int)(taxaServico * 100), finalComServico);
    }
}
Dúvidas? Escreva anonimamente sua dúvida aqui neste formulário.