Введение
Пункт отправки уже умеет получать цены, но метод сравнения пока не возвращает победителей. Вы научите его сравнивать объекты правил, сохранять все равные минимальные цены и записывать полный файл предложений для нескольких посылок.
Лабораторная запускается независимо, с двумя готовыми реализациями из предыдущей guided-лабораторной. Предполагается понимание её интерфейса, применимости и целочисленных ступенчатых тарифов. Вы добавите новый параметризованный экземпляр существующего правила, не изобретая другой алгоритм цены. Все тарифы синтетические. Время оценено автором.
Сравнивайте через интерфейс
На этом шаге вы реализуете метод сравнения для любого переданного ShippingRule, включая новую реализацию, которую сравнивающий код раньше не встречал.
Откройте вкладку WebIDE, затем выберите в меню Terminal → New Terminal, чтобы открыть встроенный терминал. Выполняйте следующие команды в нём. Они работают в одной оболочке; cd меняет её рабочий каталог. Если вы заново откроете терминал, повторите команду cd. JDK и каркас исходного кода подготовлены; устанавливать инструмент сборки не нужно.
cd /home/labex/project/parcels
./quote.sh quote 1500
Town и Steps показывают 600. Этот обычный случай равенства объясняет, почему сохранение только одного самого дешёвого правила теряет допустимый вариант. Полный публичный контракт и допустимые входы таковы:
Публичный контракт включает ShippingRule.id() и ShippingRule.quote(Parcel), а также Quote.eligible() и Quote.cents(). RuleFactory.flat(String, int, long) и RuleFactory.stepped(String, int, int, long) создают объекты правил; QuoteEngine.bestRules(Parcel, List<ShippingRule>) возвращает ID всех правил с минимальной ценой. Эти сигнатуры позволяют одному вызывающему коду использовать разные реализации. Вы можете иначе организовать классы, в том числе изменить RuleFactory для их создания. Сохраните публичные методы и предоставленный формат команд и вывода; внутренние имена классов фабрики и выбранный редактор не оцениваются.
Поддерживаются целые веса от 1 до 1,000,000 граммов. Ограничения веса и размеры ступеней также являются целыми от 1 до 1,000,000; фиксированная цена или цена одной ступени — целое от 0 до 1,000,000 центов. Подходящее предложение за ноль центов допустимо. Оно отличается от Quote.unavailable(), у которого eligible() равно false, а хранимая сумма не должна участвовать в сравнении. Рассчитанные суммы хранятся в long, поэтому большое допустимое произведение не переполнит 32-битный int. Все тарифы, персонажи и названия посылок синтетические; это не актуальные цены реальных перевозчиков.
Метод получает List<ShippingRule>. Элементы могут иметь разные реализации; расширенный цикл for обходит каждый объект. Вызывайте quote(parcel) вместо проверки названия правила или воспроизведения его бизнес-логики через instanceof.
Начните с пустого списка победителей и Long.MAX_VALUE, наибольшего long, как сторожевого значения для сравнения. Пропускайте неподходящие предложения через continue. Строго меньшая цена заменяет прежний минимум, поэтому clear() удаляет старых победителей. Равная цена добавляет свой ID. Это два отдельных оператора if: только что установленный минимум тоже должен попасть в список. Если ничего не подходит, список остаётся пустым.
Следующая команда заменяет файл исходного кода Java. cat копирует текст между двумя строками JAVA в путь после >; кавычки у начального маркера запрещают подстановки оболочки в Java-коде. Вставьте блок целиком, включая завершающий JAVA на отдельной строке. Можно также изменить этот файл в WebIDE, сохранить его и вернуться во встроенный терминал. Если неполная вставка оставила приглашение продолжения ввода, нажмите Ctrl+C и вставьте весь блок заново.
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 получает путь TSV посылок и путь TSV тарифов. Строки посылок содержат ID, отображаемое имя и целые граммы. Вывод группирует каждую посылку со всеми предложениями и строкой BEST. UNAVAILABLE означает, что одно правило не может её перевезти; BEST NONE — что не может ни одно. Допустимый пакет данных без подходящих предложений успешно заканчивается с кодом 0.
Для P02 в BEST должны быть Town и Steps; P03 тяжелее на грамм, и побеждает только Town. P01 и P02 оба называются Gift, но разные ID сохраняют их предложения отдельно. Для P04 нет подходящих правил. Сохраните каждую посылку и каждое правило, включая недоступные результаты.
Зарегистрируйте правило и сохраните полные предложения
На этом шаге вы зарегистрируете новый экземпляр фиксированной цены без изменения метода сравнения и сохраните результаты для последующего чтения в пункте отправки.
Продолжайте в терминале WebIDE в /home/labex/project/parcels. Читатель тарифов создаёт нужные реализации через RuleFactory. Поэтому ещё одна строка flat создаёт другой объект с независимыми параметрами. Сохраните исходные файлы data/ без изменений. cp создаёт рабочую копию; printf пишет текст, \t означает табуляцию, а \n завершает строку. >> добавляет в конец файла, а не заменяет его.
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 подходит до 6,000 граммов включительно за 600 центов. У P02 теперь три победителя с одинаковой ценой, а у P04 весом 6,500 граммов по-прежнему нет предложений. Вы изменили зарегистрированную коллекцию правил, и первоначальное сравнение продолжило работать.
Вывод — это настоящий результат расчёта предложений. > сохраняет стандартный вывод в файл, заменяя существующий одноимённый файл. Сохраняйте только допустимый пакет данных, поскольку оболочка открывает выходной файл ещё до проверки входа в Java:
./quote.sh batch data/parcels.tsv work/rates.tsv > work/quotes.tsv
cat work/quotes.tsv
Для каждого ID нужны одна строка PARCEL, по строке QUOTE для каждого зарегистрированного правила и строка BEST со всеми подходящими ID минимальной цены через запятую либо NONE. Суммы остаются целыми центами. Порядок правил и победителей может следовать регистрации; важны состав и связи.
Недопустимый вес отличается от допустимой посылки без предложений. Подготовленный ошибочный пример содержит BAD с нулевым весом. Парсер проверяет весь пакет данных до печати цен. Недопустимый вход завершается с кодом 2, пишет пояснение в стандартный поток ошибок и не выдаёт строк предложений. Выполните этот намеренный сбой без перенаправления поверх правильного файла:
./quote.sh batch data/invalid-parcels.tsv work/rates.tsv
Ожидается INVALID_WEIGHT BAD. Для восстановления вернитесь к допустимому файлу посылок:
./quote.sh batch data/parcels.tsv work/rates.tsv
Исходные записи посылок и тарифов и ваш правильный work/quotes.tsv остаются целыми. При ошибке компиляции исправьте и сохраните указанный файл; при ошибке пути повторите cd /home/labex/project/parcels, затем запустите снова. Скрипт каждый раз пересобирает сохранённые исходники и явно использует UTF-8, как в предыдущей лабораторной.
Проверки компилируют неизменённые копии во временных данных, включая другие допустимые параметры и реализации интерфейса. Они не дополняют недостающие результаты в вашей рабочей среде и не переписывают её. Это функциональная оценка в учебной среде, а не защита от подделки файлов администратором.
Резюме
Вы сравнили объекты интерфейса без ветвлений по перевозчикам, сохранили все равные минимальные цены и явно представили допустимое отсутствие предложений. Добавление настроенного правила использовало прежний процесс. Файл сохраняет идентичность и полный набор вариантов каждой посылки.



