https://github.com/levvolkov/inheritanceissues
12 «Наследование и расширяемость систем. Проблемы наследования»
https://github.com/levvolkov/inheritanceissues
java
Last synced: over 1 year ago
JSON representation
12 «Наследование и расширяемость систем. Проблемы наследования»
- Host: GitHub
- URL: https://github.com/levvolkov/inheritanceissues
- Owner: levvolkov
- Created: 2024-03-01T07:55:52.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2024-03-21T11:11:15.000Z (over 2 years ago)
- Last Synced: 2025-01-07T15:21:53.207Z (over 1 year ago)
- Topics: java
- Language: Java
- Homepage:
- Size: 18.6 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 12. Домашнее задание к занятию «Наследование и расширяемость систем. Проблемы наследования»
## Цель задания
1. Научиться связывать классы отношением наследования.
2. Уметь переопределять методы в классах наследников.
3. Уметь пользоваться полиморфизмом классов.
------
## Инструкция к заданию
1. Скачайте и установите профессиональный редактор кода [Intellij Idea Community Version](https://www.jetbrains.com/idea/download/).
1. Откройте IDEA и [создайте и настройте новый Maven-проект](https://github.com/netology-code/javaqa-homeworks-video/blob/javaqa-55/QA_Maven_Idea_Create.md). Под каждую задачу следует создавать отдельный проект, если обратное не сказано в условии.
2. Создайте пустой репозиторий на GitHub и свяжите его с папкой вашего проекта.
3. Правильно настройте репозиторий в плане `.gitignore`. Проигнорируйте папки `.idea` и `target` (раньше была `out`) и `.iml`-файл. Их в репозитории быть не должно.
4. Закоммитьте и запушьте созданный проект на GitHub, [настройте Github Actions](https://github.com/netology-code/javaqa-homeworks-video/blob/javaqa-55/QA_CI.md), сделайте `git pull`.
4. Выполните в IDEA задачу согласно условию.
5. Проверьте соблюдение [правил форматирования кода](https://github.com/netology-code/javaqa-homeworks-video/blob/javaqa-55/QA_Java_Idea_Format.md).
6. Убедитесь, что при запуске `mvn clean verify` (раньше было `mvn clean test`) все тесты запускаются, проходят, а сборка завершается успешно.
7. Закоммитьте и отправьте в репозиторий содержимое папки проекта.
8. Убедитесь, что CI запустился на последнем коммите и завершился успешно (зелёная галочка).
------
## Материалы, которые пригодятся для выполнения задания
1. [Наследование в Java](https://metanit.com/java/tutorial/3.5.php).
1. [Как создать Maven-проект в IDEA.](https://github.com/netology-code/javaqa-homeworks-video/blob/javaqa-55/QA_Maven_Idea_Create.md)
1. [Как отформатировать код в Java.](https://github.com/netology-code/javaqa-homeworks-video/blob/javaqa-55/QA_Java_Idea_Format.md)
1. [Как настроить CI на основе Github Actions.](https://github.com/netology-code/javaqa-homeworks-video/blob/javaqa-55/QA_CI.md)
------
## Задание 1 (обязательное)
В этом задании мы будем разрабатывать систему планировщика задач.
Вам предстоит разработать и реализовать систему классов задач с использованием наследования и протестировать готовый планировщик задач.
Задачи будут трёх видов:
* `SimpleTask` — простая задача, про неё известны только `id` (число) и `title` (название);
* `Epic` — задача, состоящая из подзадач. Про неё известны `id` (число) и `subtasks` — массив из подзадач, каждая из которых является простым текстом (`String`);
* `Meeting` — задача, описывающая назначенную встречу. Про неё известны `id` — число, `topic` — тема обсуждения, `project` — название проекта, который будут обсуждать, и `start` — дата и время старта текстом.
Все объекты задач должны быть не изменяемы — исходные данные принимать в конструкторе при создании и не иметь сеттеров (только геттеры).
Мы хотим задачи хранить в менеджере. Назовём его класс `Todos` — список дел.
Было бы удобно хранить в нём задачи не по отдельности (т. е. один массив из `SimpleTask`, другой массив из `Epic`, третий массив из `Meeting`), а в одном общем массиве.
Это позволит сильно сократить и упростить код менеджера, а также мы сможем создавать новые виды задач без изменений кода `Todos`.
Чтобы хранить все задачи в одном массиве, нам нужен такой тип ячейки, который позволит в неё положить любую из наших задач.
С этим поможет полиморфизм, для которого мы создадим класс `Task`, в который вынесем общее, что есть во всех задачах, а другие задачи от него отнаследуем:
```java
import java.util.Objects;
public class Task {
protected int id;
public Task(int id) {
this.id = id;
}
public int getId() {
return id;
}
// Ниже находятся вспомогательные методы для корректной работы equals
// Переопределять их в наследниках не нужно
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Task task = (Task) o;
return id == task.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
```
А в классах задач будет `public class SimpleTask extends Task {...`, `public class Epic extends Task {...` и `public class Meeting extends Task {...`.
Реализация наследника на примере `SimpleTask`:
```java
public class SimpleTask extends Task {
protected String title;
public SimpleTask(int id, String title) {
super(id); // вызов родительского конструктора
this.title = title; // заполнение своих полей
}
public String getTitle() {
return title;
}
}
```
Реализуйте оставшиеся два класса — `Epic` и `Meeting`.
Это позволит нам в менеджере создать единый массив хранения задач, в который мы сможем положить любую из задач:
```java
public class Todos {
private Task[] tasks = new Task[0]; // <- тут будут все задачи
/**
* Вспомогательный метод для имитации добавления элемента в массив
* @param current Массив, в который мы хотим добавить элемент
* @param task Элемент, который мы хотим добавить
* @return Возвращает новый массив, который выглядит как тот, что мы передали,
* но с добавлением нового элемента в конец
*/
private Task[] addToArray(Task[] current, Task task) {
Task[] tmp = new Task[current.length + 1];
for (int i = 0; i < current.length; i++) {
tmp[i] = current[i];
}
tmp[tmp.length - 1] = task;
return tmp;
}
/**
* Метод добавления задачи в список дел
* @param task Добавляемая задача
*/
public void add(Task task) { // <- вот здесь в параметре может лежать объект и вида SimpleTask, и вида Epic, и вида Meeting
tasks = addToArray(tasks, task);
}
public Task[] findAll() {
return tasks;
}
}
```
Проверим это следующим тестом. Поместите его в `TodosTest`-класс:
```java
@Test
public void shouldAddThreeTasksOfDifferentType() {
SimpleTask simpleTask = new SimpleTask(5, "Позвонить родителям");
String[] subtasks = { "Молоко", "Яйца", "Хлеб" };
Epic epic = new Epic(55, subtasks);
Meeting meeting = new Meeting(
555,
"Выкатка 3й версии приложения",
"Приложение НетоБанка",
"Во вторник после обеда"
);
Todos todos = new Todos();
todos.add(simpleTask);
todos.add(epic);
todos.add(meeting);
Task[] expected = { simpleTask, epic, meeting };
Task[] actual = todos.findAll();
Assertions.assertArrayEquals(expected, actual);
}
```
Теперь давайте добавим в менеджер возможность искать задачи по посковому запросу (`query`).
Подходит ли задача запросу, будет решать сама задача, для чего мы в `Task` заведём метод `matches`.
```java
/**
* Метод, проверяющий подходит ли эта задача поисковому запросу.
* Эта логика должна быть определена в наследниках, у каждого она будет своя
* @param query Поисковый запрос
* @return Ответ на вопрос, подходит ли эта задача под поисковый запрос
*/
public boolean matches(String query) {
return false;
}
```
В каждом же наследнике мы переопределим этот метод так, чтобы:
* `SimpleTask` подходил, если запрос `query` встречается в `title`;
* `Epic` подходил, если запрос `query` встречается хотя бы в одной из подзадач;
* `Meeting` подходил, если запрос `query` встречается в `topic` или `project`.
Рассмотрим на примере переопределения этого метода для класса `Meeting`.
Мы воспользуемся методом `contains`, который есть у каждого объекта типа `String`: `s1.contains(s2)` отвечает на вопрос, содержится ли текст из `s2` в тексте из `s1`.
В итоге мы может переопределить метод так:
```java
@Override
public boolean matches(String query) {
if (topic.contains(query)) {
return true;
}
if (project.contains(query)) {
return true;
}
return false;
}
```
Переопределите метод `matches` для двух оставшихся классов.
Для `SimpleTask` это можно сделать одним if, для `Epic` — циклом перебирая подзадачи и также проверяя каждую через `if`.
Напишите тесты на метод `matches` для всех трёх классов, поместите их в `TasksTest`-классе.
Теперь мы можем добавить метод поиска в сам класс `Todos`:
```java
/**
* Метод поиска задач, которые подходят под поисковый запрос
* @param query Поисковый запрос
* @return Массив из подошедших задач
*/
public Task[] search(String query) {
Task[] result = new Task[0]; // массив для ответа
for (Task task : tasks) { // перебираем все задачи
if (task.matches(query)) { // если задача подходит под запрос
result = addToArray(result, task); // добавляем её в массив ответа
}
}
return result;
}
```
Напишите тесты на метод поиска в классе `TodosTest`.
Как видите, благодаря наследованию и полиморфизму, мы смогли создать менеджер задач, который работал бы с любыми типами задач.
Мы можем создать их ещё хоть сто разных видов, и менеджер менять для этого не потребуется.
------
## Правила приёма работы
Прикреплена ссылка на публичный репозиторий с решением задачи.
------
## Критерии оценки
1. В каждом репозитории размещено содержимое папки проекта IDEA. Корнем репозитория должна быть именно папка проекта — не папка `src`, не папка, внутри которой лежит папка проекта. В корне репозитория должна лежать сразу папка `src`.
1. Есть файл `.gitignore`, игнорирующий ненужные файлы и папки, которые должны отсутствовать в репозитории. Если они там есть, их нужно оттуда удалить.
1. Программа соответствует всем требованиям из условия задачи.
1. Программа использует только те инструменты языка, которые мы проходили или которые прямо разрешены условием задачи.
1. Программа работает правильно на всех примерах из условия.
1. Программный код отформатирован и соответствует пройденным требованиям к качеству кода.
1. При запуске `mvn clean verify` тесты запускаются и проходят, а сборка завершается успешно.
2. В репозитории настроен CI на основе Github Actions, и он успешно прошёл на последнем коммите.
3. Программа спроектирована достаточно логично и правильно, не противоречит общепринятым в производстве практикам и традициям.
4. При наличии недочётов, в зависимости от их серьёзности и количества, работа может быть отправлена на доработку или принята. Решение принимается на основе экспертной оценки работы.