Projeto Académico | Padrões e Desenho de Software | IPCB 2024/2025
Sistema robusto de gestão de cupões de desconto e cartões de fidelização para a cadeia de lojas fictícia HonESTa, desenvolvido como projeto académico da disciplina de Padrões e Desenho de Software (PDS) no Instituto Politécnico de Castelo Branco.
Este projeto demonstra a aplicação prática de conceitos avançados de Programação Orientada a Objetos e Design Patterns em Java, criando um sistema completo, extensível e manutenível.
| 🏗️ Arquitetura em Camadas |
🎭 Polimorfismo Completo |
✅ Validação Robusta |
📚 Documentação Javadoc |
| 🔒 Encapsulamento Total |
🌳 Herança Hierárquica |
🧩 Composição de Classes |
🚀 Sistema Extensível |
- ⚡ Funcionalidades
- 🛠️ Tecnologias
- 🏗️ Arquitetura
- 🚀 Como Executar
- 💡 Conceitos OOP
- 📖 Exemplos de Uso
- 🧪 Testes
- 📊 Métricas
- 👨💻 Autor
- ✅ Gestão completa de cartões de clientes
- ✅ Acumulação automática de saldo através de cupões
- ✅ Ativação e desativação seletiva de cupões
- ✅ Validação automática de prazos de validade
- ✅ Atualização inteligente (remove cupões expirados automaticamente)
- ✅ Histórico detalhado de cupões disponíveis e futuros
| Tipo | Ícone | Descrição | Exemplo |
|---|---|---|---|
| Cupão de Produtos | 📦 | Desconto em produtos específicos | 15% em Massas selecionadas |
| Cupão de Marca | 🏷️ | Desconto em todos os produtos de uma marca | 10% em produtos Albicereal |
| Cupão de Compra | 🛒 | Desconto aplicado ao total da compra | 5% em qualquer compra |
- ❌ Não cumulativo - Aplica-se sempre o cupão de maior desconto
- 💰 Saldo acumulado - Descontos são convertidos em saldo no cartão
- 📅 Prazo de validade - Cupões têm data de início e fim
- 🔝 Priorização automática - Sistema escolhe automaticamente o melhor desconto
- 🎫 Um cupão por produto - Cada produto só pode ter um cupão aplicado
- ✂️ Remoção automática - Cupões usados são removidos do cartão
- 📝 Processamento de vendas com múltiplos produtos
- 🤖 Aplicação automática e inteligente de cupões ativos
- 🧮 Cálculo otimizado de descontos (maior desconto primeiro)
- 💵 Acumulação imediata de saldo no cartão do cliente
- 📊 Histórico completo de cupões utilizados por venda
- 📋 Relatório detalhado e formatado de cada transação
- 🏪 Cadastro e gestão centralizada de produtos
- 🔖 Informação completa: código, marca, modelo, preço
- 🎫 Repositório de cupões disponíveis
- 💳 Gestão de cartões de clientes
- 💯 Preços em cêntimos (evita erros de arredondamento float)
- 🔍 Busca rápida e eficiente com HashMap
java.time.* // Gestão de datas (LocalDate)
java.util.* // Collections (ArrayList, HashMap, List, Map)
java.io.* // Leitura de ficheiros (BufferedReader, FileReader)
java.util.Objects // Validação de objetos nulos✨ Zero dependências externas - 100% Java Standard Library! ✨
┌─────────────────────────────────────────────────────────────┐
│ 🎫 Coupon Engine │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 💳 │ │ 🏪 │ │ 🔧 │ │ 🖥️ │ │
│ │ cliente │ │ comercio │ │ util │ │ menu │ │
│ │ │ │ │ │ │ │ │ │
│ │ Cartao │ │ Produto │ │Validator │ │ Main │ │
│ │ Cupao* │ │ Venda │ │ │ │ │ │
│ │ Cupoes │ │Inventario│ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │ │
│ └─────────────┴──────────────┴──────────────┘ │
└─────────────────────────────────────────────────────────────┘
Cupao (abstract)
┌──────────┴──────────┐
│ │
CupaoProdutos CupaoMarca
📦 - abrangidos 🏷️ - marca
- abrange() - abrange()
│
CupaoCompra
🛒 - abrange() → true
coupon-engine/
│
├── 📝 src/ # Código fonte
│ ├── 💳 cliente/ # Camada de Cliente
│ │ ├── Cartao.java # Gestão de cartões
│ │ ├── Cupao.java # ⭐ Classe abstrata base
│ │ ├── CupaoProdutos.java # 📦 Cupão de produtos
│ │ ├── CupaoMarca.java # 🏷️ Cupão de marca
│ │ └── CupaoCompra.java # 🛒 Cupão de compra
│ │
│ ├── 🏪 comercio/ # Camada de Negócio
│ │ ├── ProdutoInfo.java # Info de produtos
│ │ ├── ProdutoVendido.java # Produto numa venda
│ │ ├── Venda.java # Processamento de vendas
│ │ └── Inventario.java # Repositório de dados
│ │
│ ├── 🔧 util/ # Utilitários
│ │ └── Validator.java # Validações centralizadas
│ │
│ └── 🖥️ menu/ # Interface
│ └── Main.java # Ponto de entrada
│
├── 📊 dados/ # Ficheiros de dados (TSV)
│ ├── produtos.hnt
│ ├── cupoes.hnt
│ └── cartoes.hnt
│
├── 🔨 bin/ # Compilados (.class)
├── 📄 .gitignore
├── 📜 LICENSE
└── 📖 README.md
- ☕ Java JDK 17 ou superior
- 💻 VS Code com Extension Pack for Java (recomendado)
- 🔧 Git configurado (opcional)
java -version # ✓ Deve mostrar versão 17+
javac -version # ✓ Deve mostrar versão 17+1️⃣ Clone o repositório
git clone https://github.com/CLopes86/coupon-engine.git
cd coupon-engine2️⃣ Abra no VS Code
code .3️⃣ Execute
- Abra
src/menu/Main.java - Clique no botão
▶️ "Run" acima do métodomain() - Ou pressione F5
# Navegar para o projeto
cd coupon-engine
# Compilar
javac -d bin -sourcepath src src/**/*.java
# Executar
java -cp bin menu.MainCrie run.sh:
#!/bin/bash
echo "🔨 Compilando..."
javac -d bin -sourcepath src src/**/*.java
if [ $? -eq 0 ]; then
echo "✅ Sucesso! Executando..."
java -cp bin menu.Main
else
echo "❌ Erro na compilação!"
fiExecute:
chmod +x run.sh
./run.shDados protegidos com acesso controlado
public class ProdutoInfo {
private String codigoBarras; // 🔒 Protected
private long preco;
public long getPreco() { // ✅ Public getter
return preco;
}
public void setPreco(long preco) { // ✅ Validated setter
if (preco < 0) {
throw new IllegalArgumentException("Preço inválido");
}
this.preco = preco;
}
}Classe base abstrata com subclasses especializadas
public abstract class Cupao {
protected String numero;
protected float desconto;
// 🎯 Método abstrato - subclasses implementam
public abstract boolean abrange(ProdutoVendido p);
}
public class CupaoProdutos extends Cupao {
@Override
public boolean abrange(ProdutoVendido p) {
return abrangidos.contains(p.getInfo());
}
}Mesmo método, comportamentos diferentes!
List<Cupao> cupoes = new ArrayList<>();
cupoes.add(new CupaoProdutos(...)); // 📦
cupoes.add(new CupaoMarca(...)); // 🏷️
cupoes.add(new CupaoCompra(...)); // 🛒
// 🎭 Cada tipo executa seu próprio método
for (Cupao c : cupoes) {
if (c.abrange(produto)) { // Comportamento depende do tipo REAL
System.out.println("Cupão aplicável!");
}
}Contrato que subclasses devem seguir
public abstract class Cupao {
// ❌ Não pode instanciar diretamente!
// ✅ Método concreto (herdado por todos)
public boolean estaValido() {
return LocalDate.now().isBefore(fim);
}
// 🎯 Método abstrato (DEVE ser implementado)
public abstract boolean abrange(ProdutoVendido p);
}Objetos contêm outros objetos (HAS-A)
public class Venda {
private List<ProdutoVendido> produtos; // HAS-A
}
public class ProdutoVendido {
private ProdutoInfo info; // HAS-A
}
public class Cartao {
private List<Cupao> cupoes; // HAS-A
}// 📋 ArrayList - Lista dinâmica
List<ProdutoVendido> produtos = new ArrayList<>();
// 🗺️ HashMap - Busca O(1)
Map<String, ProdutoInfo> produtos = new HashMap<>();
// 🔒 Lista imutável
return Collections.unmodifiableList(produtos);// Criar produtos abrangidos
List<ProdutoInfo> massas = new ArrayList<>();
massas.add(inventario.getProduto("202-006"));
massas.add(inventario.getProduto("202-007"));
// Criar cupão
Cupao cupao = new CupaoProdutos(
"1001",
"15% em massas",
massas,
0.15f, // 15% desconto
LocalDate.now(),
LocalDate.now().plusDays(7)
);
inventario.addCupao(cupao);Cupao cupao = new CupaoMarca(
"1501",
"10% em Albicereal",
0.10f,
LocalDate.now(),
LocalDate.now().plusDays(30),
"Albicereal"
);// Criar venda
Venda venda = new Venda();
inventario.vendeProduto(venda, "202-006"); // Massa
inventario.vendeProduto(venda, "125-011"); // Chocolate
// Buscar cartão
Cartao cartao = inventario.getCartao("10101");
// Ativar cupões
List<Cupao> cupoesAtivos = Arrays.asList(
inventario.getCupao("1001"),
inventario.getCupao("1003")
);
cartao.ativar(cupoesAtivos);
// ✨ Aplicar cupões e acumular saldo
cartao.usar(venda);
// Ver resultado
System.out.printf("Saldo: %.2f€%n", cartao.getSaldo() / 100.0);1️⃣ testarProdutosMarca()
- Testa cupões de produtos e marca
- Verifica priorização de descontos
- Cupões: Massas (15%), Chocolates (15%), Albicereal (10%)
2️⃣ testarProdutosCompra()
- Testa cupões específicos e cupão de compra
- Verifica cobertura de produtos sem cupão específico
- Cupões: Sumos (15%), Arroz (15%), Compra (10%)
3️⃣ testarErros()
- Valida tratamento de exceções
- Testes: Produto inexistente, Cupão inválido, Cartão não encontrado
No Main.java:
public static void main(String[] args) {
Inventario inv = new Inventario();
// ... carregar dados ...
testarProdutosMarca(inv); // ✅ Executar teste 1
// testarProdutosCompra(inv); // Teste 2
// testarErros(inv); // Teste 3
}| Métrica | Valor |
|---|---|
| Linhas de Código | ~2000+ |
| Classes Principais | 11 |
| Métodos Públicos | 120+ |
| Packages | 4 |
| Cenários de Teste | 3 |
| Cobertura OOP | 100% |
| Tempo de Desenvolvimento | 4 semanas |
| Documentação | ✅ Completa |
✅ Encapsulamento ✅ Herança ✅ Polimorfismo
✅ Abstração ✅ Composição ✅ Design Patterns
✅ Collections ✅ Exception Handling ✅ File I/O
✅ Git & GitHub ✅ Javadoc ✅ Clean Code
✅ Arquitetura ✅ Validações ✅ Documentação
🎓 Estudante de Informática e Multimédia
🏫 Instituto Politécnico de Castelo Branco
📚 Disciplina: Padrões e Desenho de Software
📅 Ano Letivo: 2024/2025
💻 Foco: Mobile Development com Flutter
🔥 Paixão: Criar aplicações que resolvem problemas reais
🚀 Objetivo: Junior Developer Position
Este projeto está sob a licença MIT. Veja LICENSE para detalhes.
- 🏫 IPCB - Pela excelente formação académica
- 👨🏫 Docentes de PDS - Pelo conhecimento partilhado
- ☕ Comunidade Java - Pelos recursos e documentação
- 💻 Stack Overflow - Pelas soluções e discussões
- 📖 Java Documentation
- 📘 Java Tutorials - Oracle
- 🎓 Effective Java - Joshua Bloch
- 💬 Stack Overflow - Java
Contribuições são bem-vindas! Para contribuir:
- 🍴 Fork o projeto
- 🌿 Crie uma branch (
git checkout -b feature/NovaFeature) - 💾 Commit as mudanças (
git commit -m 'Adiciona NovaFeature') - 📤 Push para a branch (
git push origin feature/NovaFeature) - 🎉 Abra um Pull Request