Домашнее задание к занятию «Интерфейсы для организации малой связности. Обобщённое программирование (Generics)»
Перед тем как отправить своё решение на проверку преподавателю, сверьтесь с чеклистом.
1. В решении выполнены все требования задания
Убедитесь, что все требования задания выполнены. Для этого перед отправкой внимательно прочтите весь текст условия задания и соотнесите сказанное в нём с вашим решением. Навык самопроверки работы перед ревью пригодится вам как при обучении, так и на работе.
2. Правильно настроен Maven-проект, тесты проходят
Репозиторий должен быть папкой вашего Мавен-проекта. Обратите внимание, что репозиторием не должна быть папка, в которой лежит папка Мавен-проекта, он сам должен быть папкой проекта. В нём должны быть соответствующие файлы и папки — pom.xml
, src
и другие.
Не забудьте создать .gitignore-файл в корне проекта и добавить туда в игнорирование автогенерируемую папку target
.
Общая схема вашего pom.xml
-файла:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.netology</groupId>
<artifactId>НАЗВАНИЕ-ВАШЕГО-ПРОЕКТА-БЕЗ-ПРОБЕЛОВ</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
...
</dependency>
...
</dependencies>
<build>
<plugins>
<plugin>
...
</plugin>
<plugin>
...
<executions>
<execution>
...
</execution>
...
</executions>
</plugin>
...
</plugins>
</build>
</project>
Обратите внимание, что у артефакта нет -api
на конце. Если у вас автоматически добавилась зависимость вида <artifactId>junit-jupiter-api</artifactId>
, то лучше поменять артефакт на тот, что ниже, иначе будут сюрпризы в работе.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
Без этого плагина тесты могут Мавеном не запускаться, хоть в идее через кнопки они и будут проходить. Чтобы лишний раз убедиться, что всё работает, нажмите Ctrl+Ctrl
и затем mvn clean test
.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<failIfNoTests>true</failIfNoTests>
</configuration>
</plugin>
3. Что делать, если возникли сложности
Это здорово. Если их преодолевать правильно, то можно получить большую образовательную пользу для себя. Периодическое возникновение вопросов, недопонимание пройденного материала — нормальная и неотъемлемая часть обучения. А мы здесь, чтобы помочь вам пройти этот путь.
- Если подобный вопрос разбирался на лекции, посмотрите ещё раз раздел с этой темой в видеозаписи.
- Если вопрос не решился, попробуйте поискать ответ самостоятельно в интернете, этот навык пригодится вам в работе.
- Если самостоятельно разобраться не удалось, задайте вопрос в общем чате, мы обязательно поможем.
- Прежде чем задать вопрос по условию задачи, перечитайте его ещё раз и убедитесь, что в тексте условия нет прямого ответа на этот вопрос. Умение работать с текстом — важный навык работы с информацией.
- Если ответа на свой вопрос в тексте условия не увидели, задайте его в общем чате, мы раскроем детали условия.
Если ваша проблема — это ошибка компиляции — подчёркивает красным, не даёт запустить программу, сборки проекта, CI и прочие подобные ошибки, то:
- Найдите и прочитайте текст ошибки, который вам подсвечивает идея или логи. «Подчёркивает красным» — это не описание ошибки.
- Попробуйте понять текст ошибки, при необходимости воспользуйтесь переводчиком. Не страшно, если вы переведёте неточно, тут главное — сам процесс: со временем и с нашей помощью вы будете это делать лучше и лучше, но, пропуская этот этап, вы не сможете научиться это делать.
- Если не получилось понять ошибку по её тексту, попробуйте её загуглить и изучить подобную ошибку у других людей. Попробуйте примерить решения их проблем на свой код. Соотнесите найденные описания ошибки с пройденной теорией.
- Если всё равно ваши трудности не разрешились, напишите в общий чат, обязательно указав:
- название задачи и ссылку на условие;
- ссылку на вашу работу;
- текст и скриншот, не фотографию, ошибки;
- ваши размышления и описание шагов, которые вы совершили для решения.
Если ваша проблема — это ошибка исполнения, программа умирает уже после запуска, или она отрабатывает неправильно, из-за чего ваши тесты не проходят, то:
- Воспользуйтесь отладчиком для пошагового анализа работы вашей программы. Так вы или убедитесь в неправильности придуманного вами алгоритма, или найдёте конкретное место, где ожидаемое поведение программы разошлось с фактическим.
- Если проблему найти не получилось, напишите в общий чат, обязательно указав:
- название задачи и ссылку на условие;
- ссылку на вашу работу;
- конкретное и подробное описание проблемы или затруднения при решении задачи. «Помогите, что-то не так» — это не описание;
- подробное описание вашего анализа программы с помощью отладчика вместе со скринами;
- ваши размышления и описание шагов, которые вы совершили для решения.
4. Отформатирован код
Кроме правил, нарушение которых приводит к ошибкам компиляции, есть ещё и правила форматирования кода, соблюдение которых обязательно при написании программ.
С большинством проблем может справиться автоформатирование в идее. Для этого выберите Code -> Reformat code
в меню или используйте горячие сочетания клавиш. В меню будет показано актуальное сочетание для вашей операционной системы. Так, идея поправит неправильные отступы, пробелы и некоторые другие ошибки. Следите, чтобы у if-else
, for
, while
всегда были {}
.
Проблемы с именованием сущностей нужно решать самим. Так, все ячейки, кроме final
-констант, и методы должны писаться камелкейсом с маленькой буквы, а классы и интерфейсы — камелкейсом с большой буквы.
Мы вам настоятельно советуем всегда держать код в отформатированном виде во время разработки, со временем глаз привыкнет, и вы почувствуете, насколько это облегчает поиск ошибок в коде и его анализ. В любом случае перед отправкой кода на проверку его обязательно нужно отформатировать, иначе он может быть отправлен на доработку без более глубокой проверки на этой итерации.
5. Настроен Github CI с verify-сборкой Maven и JaCoCo в режиме генерации отчётов с покрытием на 100% по бранчам методов с логикой [:warning:: в этом задании можно не покрывать на 100%]
После связывания локального репозитория с удалённым и первого пуша в заготовки проекта, время настроить CI на основе GitHub Actions. Шаблон вашего maven.yml должен выглядеть вот так, убедитесь, что всё совпадает с вашим шаблоном, например, что вы указали фазу verify
, а не package
:
name: Java CI with Maven
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
- name: Build with Maven
run: mvn -B -e verify
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
...
Инициализация:
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
В режиме генерации отчётов:
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
В режиме проверки и обрушения сборки по уровню покрытия:
<execution>
<id>check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>100%</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
Вы работаете в сервисе по продаже авиабилетов онлайн.
Что вам нужно сделать:
- Спроектируйте класс для информации о билете.
- Реализуйте репозиторий для хранения информации о билетах: добавить, удалить, получить набор билетов.
- Реализуйте менеджера поиска по аэропорту вылета и аэропорту прилёта, даты не учитывайте.
Класс информации о билете — это data-класс, который должен содержать:
- ID.
- Стоимость, для упрощения будем считать стоимость единой для всех продавцов.
- Аэропорт вылета, вы можете использовать IATA-коды.
- Аэропорт прилёта, вы можете использовать IATA-коды.
- Время в пути в минутах.
Других данных не нужно.
Этот класс должен реализовывать интерфейс Comparable<...>
так, чтобы по умолчанию сортировка происходила по цене, самый дешёвый — самый первый. Для этого шапка вашего дата-класса должна выглядеть как-то так:
public class Ticket implements Comparable<Ticket> {
После чего идея подсветит вам её красным, нажмите на подсказку и выберите «Implement methods» — «Реализовать методы». Идея сама сгенерирует заглушку для нужного метода из этого интерфейса, которая всегда возвращает 0
. Вам надо переписать тело сгенерированного метода, чтобы если билет, у которого вызвали метод compareTo
, стоит дешевле, чем тот, который передали через параметр, то возвращалось бы число меньше нуля. Если же билет, наоборот, дороже, то число больше нуля, а если стоимость одинакова, то 0
. Дав верную реализацию этому методу, вы научите Java сравнивать объекты этого класса.
Репозиторий для хранения билетов ничем не отличается от тех репозиториев, что мы проходили раньше.
В менеджере методов findAll
должен претерпеть некоторые изменения — он должен принимать два параметра:
from
— аэропорта вылета,to
— аэропорт прилёта.
Значит, в результате поиска возвращается массив только с теми билетами, что соответствуют условиям поиска. Методы поиска вы уже делать умеете.
Кроме того, результаты должны быть отсортированы по цене от меньшей к большей.
Напишите автотесты на поиск, удостоверившись, что он удовлетворяет условиям задачи. Количество тестов и тестируемые сценарии мы оставляем на ваше усмотрение.
Итого: у вас должен быть репозиторий на GitHub, в котором расположен ваш Java-код и автотесты к нему, GitHub Actions и т. д. — всё как обычно.
Отправьте на проверку ссылку на репозиторий GitHub с вашим проектом.
Иногда необходима сортировка не только по цене, но и, например, по времени — люди хотят найти самый быстрый перелёт.
Естественно, ваш сервис идёт навстречу пожеланиям клиентов и решает добавить такую возможность.
Но как мы это сделаем, ведь наши билеты уже сортируются по цене.
Помимо интерфейса Comparable
, который определяет порядок сортировки объектов данного класса по умолчанию, у нас есть интерфейс Comparator
, который позволяет создавать объекты, определяющие порядок сортировки других объектов.
Как это выглядит, мы покажем на примере сортировки по цене по возрастанию — аналог, который реализован вами в первой задаче:
public class TicketByPriceAscComparator implements Comparator<Ticket> {
public int compare(Ticket o1, Ticket o2) {
return o1.getPrice() - o2.getPrice();
}
}
Обратите внимание: это отдельный специальный класс, который умеет сравнивать два объекта типа «Билет».
Логика интерпретации возвращаемого из метода compare
значения аналогична логике compareTo
.
В отдельной ветке fast
того же репозитория улучшите сервис, создав метод findAll(String from, String to, Comparator<Ticket> comparator)
.
Этот метод делает всё то же самое, что и обычный findAll
из первой задачи, но сортирует не методом Arrays.sort(result)
, а Arrays.sort(result, comparator)
.
Таким образом, вы сможете передавать в этот метод объект любого класса, реализующего интерфейс Comparator<Ticket>
.
Итого: у вас должен быть репозиторий на GitHub, в котором в отдельной ветке расположен ваш компаратор, сервис с новыми методами и автотесты к сервису.
Если автотесты в ветке проходят — делаете Pull Request на слияние в основную ветку. Сливать не нужно.
При отправке решения в личном кабинете прикрепите ссылку на ваш публичный репозиторий GitHub с вашим проектом.