Introdução
Um pequeno balcão de encomendas precisa comparar ofertas de diferentes regras de envio. Para um pacote de 500 gramas, os dados preparados indicam 600 centavos com Town e 200 com Steps. Você fará essas ofertas normais funcionarem e depois examinará o limite de peso que altera um preço.
Este laboratório pressupõe conhecimentos de classes, construtores, métodos, listas e polimorfismo básico em Java. Ele apresenta uma interface e um resultado de cotação explícito. O analisador e o script de execução são fornecidos; você implementa as decisões reais de elegibilidade e preço. O tempo estimado pelo autor inclui leitura e correções comuns.
Dar um contrato público a uma regra de preço fixo
Nesta etapa, você fará a regra Town retornar um preço real para pacotes elegíveis e rejeitar os que ultrapassam o peso máximo.
Abra a aba WebIDE e escolha Terminal → New Terminal no menu para abrir o terminal integrado. Execute os próximos comandos nesse terminal do WebIDE. Todos usam o mesmo shell; cd altera o diretório de trabalho dele. Se abrir outro terminal, repita o comando cd. O JDK e a estrutura de código estão preparados; não é necessário instalar uma ferramenta de build.
cd /home/labex/project/parcels
cat exibe um arquivo sem alterá-lo. Leia o pequeno arquivo de tarifas e a interface:
cat data/rates.tsv
cat src/ShippingRule.java
O arquivo usa TSV: campos separados por tabulações, sem cabeçalho. Uma linha flat contém type, ID da regra, máximo em gramas e centavos. Uma linha step acrescenta o tamanho da faixa antes dos centavos por faixa. Town aceita até 2,000 gramas e cobra 600 centavos; Steps aceita até 5,000 e cobra 200 centavos por faixa de 500 gramas iniciada.
Uma interface descreve os métodos que o chamador pode usar sem conhecer a classe de implementação. ShippingRule promete um ID e uma cotação para um pacote. Uma classe declara implements ShippingRule e fornece os dois métodos públicos. Ao chamar rule.quote(parcel), a implementação correspondente ao objeto é escolhida em tempo de execução. Não são necessárias conversões de tipo nem condições por nome da transportadora.
O contrato público inclui ShippingRule.id() e ShippingRule.quote(Parcel), além de Quote.eligible() e Quote.cents(). RuleFactory.flat(String, int, long) e RuleFactory.stepped(String, int, int, long) criam objetos de regras; QuoteEngine.bestRules(Parcel, List<ShippingRule>) retorna os IDs de todas as regras vencedoras. Essas assinaturas permitem ao mesmo código chamador usar implementações diferentes. Você pode organizar as classes de outra maneira e alterar RuleFactory para construí-las. Mantenha esses métodos públicos e o formato de comandos e saída fornecido; os nomes das classes internas da fábrica e o editor escolhido não são avaliados.
Os pesos aceitos são inteiros de 1 a 1,000,000 gramas. Os limites de peso e os tamanhos das faixas também são inteiros de 1 a 1,000,000; cada preço fixo ou por faixa é um inteiro de 0 a 1,000,000 centavos. Uma oferta elegível de zero centavos é válida. Ela difere de Quote.unavailable(), cujo eligible() é false e cujo valor armazenado não deve participar da comparação. Um long armazena os centavos calculados, evitando que um produto grande válido transborde um int de 32 bits. Todas as tarifas, pessoas e nomes de pacotes são sintéticos; não são preços de transportadoras consultados em tempo real.
Parcel já mantém ID, nome de exibição e gramas em campos privados, com métodos somente de leitura. Quote.priced(cents) cria um resultado elegível; Quote.unavailable() cria um inelegível. O construtor de FlatRule guarda os parâmetros. Complete seu método quote verificando a elegibilidade antes de retornar um preço. return encerra o método imediatamente; > mantém elegível um pacote exatamente no limite.
O comando a seguir substitui um arquivo-fonte Java. cat copia o texto entre as duas linhas JAVA para o caminho após >; as aspas do marcador inicial impedem substituições do shell no código Java. Cole o bloco completo, incluindo o último JAVA sozinho na linha. Você também pode editar o mesmo arquivo no WebIDE, salvá-lo e voltar ao terminal do WebIDE. Se uma colagem incompleta deixar um prompt de continuação, pressione Ctrl+C e cole o bloco inteiro novamente.
cat > src/FlatRule.java <<'JAVA'
public final class FlatRule implements ShippingRule {
private final String id;
private final int maxGrams;
private final long cents;
public FlatRule(String id, int maxGrams, long cents) {
this.id = id; this.maxGrams = maxGrams; this.cents = cents;
}
public String id() { return id; }
public Quote quote(Parcel parcel) {
if (parcel.grams() > maxGrams) return Quote.unavailable();
return Quote.priced(cents);
}
}
JAVA
./quote.sh executa o script fornecido no diretório atual. Ele compila src/*.java com javac -encoding UTF-8 em um diretório temporário e inicia Java com codificação UTF-8. Cada execução recompila as fontes salvas, sem reutilizar arquivos de classe antigos. Um erro de compilação indica arquivo e linha: corrija o arquivo, salve e repita o comando. Um caminho incorreto causa um erro de arquivo; repita o cd indicado e confira o nome, sem reinicializar o ambiente.
./quote.sh quote 500
O comando quote recebe um peso em gramas e mostra cada ID de regra com centavos ou UNAVAILABLE. Town deve mostrar 600. Steps ainda mostra 0 porque seu método inicial está incompleto de propósito; isso não é uma oferta gratuita real.
Teste o máximo e um grama acima:
./quote.sh quote 2000
./quote.sh quote 2001
Town muda de 600 para UNAVAILABLE. Você preservou o máximo inclusivo sem alterar data/rates.tsv. Verifique esta etapa antes de continuar.
Cobrar por cada faixa de peso iniciada
Nesta etapa, você implementará a segunda regra pela mesma interface, usando aritmética inteira em vez de valores monetários de ponto flutuante.
Continue no terminal do WebIDE, em /home/labex/project/parcels. Cada faixa de 500 gramas iniciada custa 200 centavos: 1–500 gramas usam uma faixa, 501–1,000 usam duas e 1,001–1,500 usam três. Portanto, 500 gramas custam 200 centavos, enquanto 501 custam 400. A divisão inteira comum trunca: 501 / 500 resulta em 1, cobrando menos do que deveria.
Para pesos positivos, (grams + stepGrams - 1L) / stepGrams arredonda a quantidade de faixas para cima. L faz a operação usar long; multiplicar a quantidade por stepCents também usa long. O limite máximo é verificado primeiro, para não dar um preço enganoso a um pacote fora do serviço.
Substitua todo o arquivo da regra por esta implementação, usando a mesma técnica here-document de antes:
cat > src/StepRule.java <<'JAVA'
public final class StepRule implements ShippingRule {
private final String id;
private final int maxGrams, stepGrams;
private final long stepCents;
public StepRule(String id, int maxGrams, int stepGrams, long stepCents) {
this.id = id; this.maxGrams = maxGrams;
this.stepGrams = stepGrams; this.stepCents = stepCents;
}
public String id() { return id; }
public Quote quote(Parcel parcel) {
if (parcel.grams() > maxGrams) return Quote.unavailable();
long steps = (parcel.grams() + stepGrams - 1L) / stepGrams;
return Quote.priced(steps * stepCents);
}
}
JAVA
./quote.sh quote 500
Saída esperada, com colunas separadas por tabulações:
Town 600
Steps 200
Agora atravesse uma fronteira de faixa e o limite de elegibilidade:
./quote.sh quote 501
./quote.sh quote 5001
Com 501 gramas, Steps mostra 400. Com 5,001, as duas regras mostram UNAVAILABLE: o peso é válido, mas não há oferta; o pacote não é inválido. Experimente zero gramas de propósito:
./quote.sh quote 0
Este comando falha intencionalmente com INVALID_WEIGHT SAMPLE e status de saída 2. Ele não altera as fontes nem as tarifas. Para se recuperar, basta fornecer um peso válido:
./quote.sh quote 1500
As duas regras agora mostram 600. Você tem um empate real para tratar no próximo laboratório. As decisões de elegibilidade e preço estão dentro dos objetos de regras substituíveis, enquanto o chamador continua usando somente a interface.
Resumo
Você implementou duas regras por trás de uma interface Java, separou a elegibilidade dos valores inteiros em centavos e testou limites exatos e arredondamento de faixas iniciadas. O mesmo chamador agora obtém cotações úteis sem saber qual implementação as fornece.



