Comparar reglas de envío sustituibles

JavaBeginner
Practicar Ahora

Introducción

El mostrador ya obtiene precios, pero su método de comparación todavía no devuelve ganadores. Harás que compare objetos de reglas, conserve todos los empates de precio mínimo y guarde un archivo completo de cotizaciones para varios paquetes.

Este laboratorio empieza de forma independiente con las dos reglas del laboratorio guiado anterior ya implementadas. Presupone sus conocimientos de interfaz, aptitud y tarifas por tramos enteros. Añadirás una nueva instancia parametrizada de una regla existente, sin inventar otro algoritmo de precios. Todas las tarifas son sintéticas. El tiempo es una estimación del autor.

Comparar mediante la interfaz

En este paso, implementarás un método de comparación que funcione con cualquier ShippingRule proporcionada, incluida una implementación que el comparador nunca haya visto.

Abre la pestaña WebIDE y selecciona Terminal → New Terminal en el menú para abrir la terminal integrada. Ejecuta allí los siguientes comandos. Todos usan la misma sesión de shell; cd cambia su directorio de trabajo. Si vuelves a abrir una terminal, repite el comando cd. El JDK y el código de base están preparados; no necesitas instalar una herramienta de compilación.

cd /home/labex/project/parcels
./quote.sh quote 1500

Town y Steps muestran 600. Este empate normal explica por qué guardar solo una regla más barata eliminaría una opción válida. El contrato público y de entrada completo es el siguiente:

El contrato público incluye ShippingRule.id() y ShippingRule.quote(Parcel), junto con Quote.eligible() y Quote.cents(). RuleFactory.flat(String, int, long) y RuleFactory.stepped(String, int, int, long) crean objetos de reglas; QuoteEngine.bestRules(Parcel, List<ShippingRule>) devuelve los ID de todas las reglas ganadoras. Estas firmas permiten que el mismo código cliente use implementaciones distintas. Puedes organizar las clases de otra forma y modificar RuleFactory para crearlas. Conserva estos métodos públicos y el formato de comandos y salida proporcionado; no se evalúan los nombres de las clases internas de la fábrica ni el editor que uses.

Los pesos admitidos son enteros de 1 a 1,000,000 gramos. Los límites de peso y los tamaños de tramo también son enteros de 1 a 1,000,000; cada tarifa fija o por tramo es un entero de 0 a 1,000,000 céntimos. Una oferta apta de cero céntimos es válida. Se distingue de Quote.unavailable(), cuyo eligible() es false y cuyo importe almacenado no debe participar en la comparación. Los importes calculados se guardan en un long, de modo que un producto grande válido no desborde un int de 32 bits. Todas las tarifas, personas y denominaciones de paquetes son datos sintéticos; no son precios en directo de transportistas.

El comparador recibe una List<ShippingRule>. Cada elemento puede tener una implementación diferente; un bucle for mejorado visita todos los objetos. Llama a quote(parcel) en lugar de comprobar nombres de reglas o usar instanceof para reproducir su lógica de negocio.

Empieza con una lista de ganadores vacía y Long.MAX_VALUE, el mayor long, como valor centinela. Omite las ofertas no aptas con continue. Un precio estrictamente menor sustituye al mínimo anterior, por lo que clear() elimina los antiguos ganadores. Un precio igual añade su ID. Son dos instrucciones if independientes: también hay que añadir el nuevo mínimo recién establecido. Si nada cumple las condiciones, la lista queda vacía.

El siguiente comando sustituye un archivo fuente Java. cat copia el texto situado entre las dos líneas JAVA a la ruta indicada después de >; las comillas del marcador inicial impiden que el shell sustituya expresiones del código Java. Pega el bloque completo, incluida la última línea JAVA, que debe estar sola. También puedes editar el mismo archivo en WebIDE, guardarlo y volver a la terminal de WebIDE. Si una copia incompleta deja un indicador de continuación, pulsa Ctrl+C y pega de nuevo el bloque completo.

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 recibe una ruta TSV de paquetes y otra de tarifas. Las filas de paquetes contienen ID, nombre mostrado y gramos enteros. La salida agrupa cada paquete con todas sus ofertas y una fila BEST. UNAVAILABLE significa que una regla no puede transportarlo; BEST NONE significa que ninguna puede. Un lote válido sin ofertas aptas termina correctamente, con estado 0.

Para P02, Town y Steps deben aparecer en BEST; P03 pesa un gramo más y solo gana Town. P01 y P02 se llaman Gift, pero sus ID distintos mantienen separadas sus cotizaciones. P04 no tiene ninguna regla apta. Conserva todos los paquetes y todas las reglas, incluidos los resultados no disponibles.

Registrar otra regla y conservar cotizaciones completas

En este paso, registrarás una nueva instancia de tarifa fija sin modificar el comparador y guardarás resultados que el mostrador podrá leer después.

Continúa en la terminal de WebIDE, en /home/labex/project/parcels. El lector de tarifas usa RuleFactory para construir las implementaciones solicitadas. Por eso, otra fila flat crea otro objeto con parámetros independientes. Conserva sin cambios los archivos originales de data/. cp crea una copia de trabajo; printf escribe texto, \t representa una tabulación y \n termina la fila. >> añade al archivo en lugar de reemplazarlo.

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 es apta hasta 6,000 gramos inclusive y cobra 600 céntimos. P02 tiene ahora tres ganadores empatados, mientras P04, de 6,500 gramos, sigue sin ofertas. Cambiaste la colección de reglas registradas y el código de comparación original siguió funcionando.

La salida es el entregable real de cotización. > guarda la salida estándar en un archivo y sustituye uno existente con ese nombre. Guarda únicamente un lote válido, porque el shell abre ese archivo antes de que Java valide las entradas:

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

Cada ID debe tener una fila PARCEL, una fila QUOTE por regla registrada y una fila BEST con todos los ID aptos de precio mínimo separados por comas, o NONE. Los importes siguen siendo céntimos enteros. Las reglas y los ganadores pueden seguir el orden de registro; lo importante son los miembros y sus relaciones.

Un peso inválido es distinto de un paquete válido sin ofertas. El ejemplo inválido preparado contiene BAD con cero gramos. El analizador valida el lote completo antes de imprimir cotizaciones; un lote inválido sale con estado 2, escribe un error explicativo en la salida de error estándar y no produce filas de cotización. Ejecuta este fallo intencionado sin redirigirlo sobre tu archivo correcto:

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

Espera INVALID_WEIGHT BAD. Para recuperarte, vuelve al archivo de paquetes válido:

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

Los registros originales de paquetes y tarifas y tu archivo correcto work/quotes.tsv permanecen intactos. Corrige y guarda el archivo indicado ante un error de compilación o repite cd /home/labex/project/parcels ante un error de ruta; después vuelve a ejecutar. El lanzador recompila las fuentes guardadas en cada ejecución y usa UTF-8 explícitamente, igual que en el laboratorio anterior.

Las comprobaciones compilan copias sin modificar en ejemplos temporales, con otros parámetros e implementaciones de interfaz válidos. No completan resultados que falten en el entorno ni reescriben el espacio de trabajo. Es una evaluación funcional en un entorno de formación, no una protección contra un administrador que falsifique archivos.

Resumen

Comparaste objetos de interfaz sin ramas específicas por transportista, conservaste todos los precios mínimos empatados y representaste explícitamente una ausencia válida de ofertas. Añadir una regla configurada reutilizó el mismo flujo. El archivo guardado conserva la identidad y todas las opciones de cada paquete.