Comparar regras de envio substituíveis

JavaBeginner
Pratique Agora

Introdução

O balcão já obtém preços, mas seu método de comparação ainda não retorna vencedores. Você fará com que ele compare objetos de regras, preserve todos os empates de menor preço e salve um arquivo completo de cotações para vários pacotes.

Este laboratório começa de forma independente com as duas regras do laboratório guiado anterior já preparadas. Ele pressupõe os conhecimentos de interface, elegibilidade e preços por faixas inteiras daquele laboratório. Você acrescentará uma nova instância parametrizada de uma regra existente, sem inventar outro algoritmo de cobrança. Todas as tarifas são sintéticas. O tempo é uma estimativa do autor.

Comparar por meio da interface

Nesta etapa, você implementará um método de comparação que funciona com qualquer ShippingRule fornecida, inclusive uma implementação que o comparador nunca viu.

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
./quote.sh quote 1500

Town e Steps mostram 600. Esse empate normal explica por que manter apenas uma regra mais barata perderia uma opção válida. O contrato público e de entrada completo é:

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.

O comparador recebe uma List<ShippingRule>. Cada elemento pode ter uma implementação diferente; um laço for aprimorado visita todos os objetos. Chame quote(parcel) em vez de verificar o nome da regra ou usar instanceof para reproduzir sua lógica de negócio.

Comece com uma lista de vencedores vazia e Long.MAX_VALUE, o maior long, como sentinela de comparação. Pule ofertas inelegíveis com continue. Um preço estritamente menor substitui o mínimo anterior, então clear() remove os antigos vencedores. Um preço igual acrescenta seu ID. São duas instruções if separadas: um mínimo recém-estabelecido também precisa ser acrescentado. Se nada for elegível, a lista permanece vazia.

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/QuoteEngine.java <<'JAVA'
import java.util.ArrayList;
import java.util.List;
public final class QuoteEngine {
    public static List<String> bestRules(Parcel parcel, List<ShippingRule> rules) {
        List<String> winners = new ArrayList<>();
        long lowest = Long.MAX_VALUE;
        for (ShippingRule rule : rules) {
            Quote quote = rule.quote(parcel);
            if (!quote.eligible()) continue;
            if (quote.cents() < lowest) {
                lowest = quote.cents();
                winners.clear();
            }
            if (quote.cents() == lowest) winners.add(rule.id());
        }
        return winners;
    }
}
JAVA
./quote.sh batch data/parcels.tsv data/rates.tsv

batch recebe um caminho TSV de pacotes e um caminho TSV de tarifas. As linhas de pacotes são ID, nome de exibição e gramas inteiros. A saída agrupa cada pacote com todas as cotações e uma linha BEST. UNAVAILABLE indica que uma regra não pode transportá-lo; BEST NONE, que nenhuma pode. Um lote válido sem oferta elegível termina com sucesso, status 0.

Para P02, Town e Steps precisam estar em BEST; P03 pesa um grama a mais e somente Town vence. P01 e P02 se chamam Gift, mas os IDs diferentes mantêm as cotações separadas. P04 não tem regra elegível. Preserve todos os pacotes e regras, inclusive os resultados indisponíveis.

Registrar outra regra e manter cotações completas

Nesta etapa, você registrará uma nova instância de preço fixo sem alterar o comparador e salvará resultados para o balcão consultar depois.

Continue no terminal do WebIDE, em /home/labex/project/parcels. O leitor de tarifas usa RuleFactory para construir as implementações pedidas. Assim, outra linha flat cria outro objeto com parâmetros independentes. Mantenha os arquivos originais de data/ intactos. cp cria uma cópia de trabalho; printf escreve texto, \t representa uma tabulação e \n encerra a linha. >> acrescenta ao arquivo em vez de substituí-lo.

cp data/rates.tsv work/rates.tsv
printf 'flat\tRelay\t6000\t600\n' >> work/rates.tsv
./quote.sh batch data/parcels.tsv work/rates.tsv

Relay é elegível até 6,000 gramas inclusive, por 600 centavos. P02 agora tem três vencedores empatados, enquanto P04, com 6,500 gramas, continua sem ofertas. Você mudou a coleção registrada, e o código de comparação original continuou funcionando.

A saída é o entregável real de cotação. > salva a saída padrão em um arquivo e substitui um arquivo existente com esse nome. Salve apenas um lote válido, pois o shell abre esse arquivo antes de Java validar as entradas:

./quote.sh batch data/parcels.tsv work/rates.tsv > work/quotes.tsv
cat work/quotes.tsv

Cada ID deve ter uma linha PARCEL, uma QUOTE por regra registrada e uma BEST com todos os IDs elegíveis de preço mínimo separados por vírgulas, ou NONE. Os valores continuam sendo centavos inteiros. Regras e vencedores podem seguir a ordem de registro; o importante são os membros e suas relações.

Um peso inválido é diferente de um pacote válido sem oferta. O exemplo inválido fornecido contém BAD com zero gramas. O analisador valida o lote inteiro antes de imprimir cotações. Um lote inválido termina com status 2, escreve uma explicação na saída de erro padrão e não produz linhas de cotação. Execute essa falha intencional sem redirecioná-la sobre seu arquivo correto:

./quote.sh batch data/invalid-parcels.tsv work/rates.tsv

Espere INVALID_WEIGHT BAD. Para se recuperar, volte ao arquivo válido de pacotes:

./quote.sh batch data/parcels.tsv work/rates.tsv

Os registros originais de pacotes e tarifas e seu work/quotes.tsv correto permanecem intactos. Corrija e salve o arquivo indicado em caso de erro de compilação, ou repita cd /home/labex/project/parcels para corrigir o caminho, e execute novamente. O script recompila as fontes salvas a cada execução e usa UTF-8 explicitamente, como no laboratório anterior.

As verificações compilam cópias inalteradas em dados temporários, incluindo outros parâmetros e implementações de interface válidos. Elas não completam resultados ausentes no ambiente nem reescrevem o espaço de trabalho. É uma avaliação funcional em um ambiente de treinamento, não uma proteção contra um administrador que falsifique arquivos.

Resumo

Você comparou objetos de interface sem condições específicas por transportadora, manteve todos os empates de menor preço e representou explicitamente a ausência válida de ofertas. Acrescentar uma regra configurada reutilizou o mesmo fluxo. O arquivo salvo preserva a identidade e todas as opções de cada pacote.