Files

327 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Техническое задание: обновление `Student`
## Задача
Обновить класс `Student` и связанный с ним код в соответствии с новой моделью данных и требованиями к неизменяемости объекта.
Текущая реализация содержит:
```java
private final String groupNumber;
private final double averageGrade;
private final String recordBookNumber;
```
Необходимо изменить тип `recordBookNumber` и добавить методы создания изменённых копий `Student`.
## Изменения в `Student`
### 1. Изменить тип `recordBookNumber`
Поле:
```java
private final String recordBookNumber;
```
заменить на:
```java
private final int recordBookNumber;
```
Метод:
```java
getRecordBookNumber()
```
должен возвращать `int`.
Все проверки, `equals()`, `hashCode()` и `toString()` должны быть адаптированы под новый тип.
### 2. Добавить бизнес-правило для `groupNumber`
`groupNumber` должен соответствовать строго следующему формату:
```text
<Заглавная буква латинского алфавита><2 цифры>
```
Регулярное выражение:
```text
^[A-Z][0-9]{2}$
```
Допустимые значения:
```text
A12
B32
Z00
```
Недопустимые значения:
```text
а12
a12
A1
A123
AA1
а1А
аа!!а123
23фи!12
№№###*()
```
Проверка должна выполняться при создании `Student`.
`Student` не может существовать с некорректным `groupNumber`.
### 3. Проверить `averageGrade`
Сохранить правило:
```text
0.0 <= averageGrade <= 5.0
```
Значения `0.0` и `5.0` допустимы.
### 4. Проверить `recordBookNumber`
После преобразования в `int` установить бизнес-правило:
```text
recordBookNumber > 0
```
Значение `0` и отрицательные значения считаются недопустимыми.
---
# Методы `with...()`
Добавить методы, возвращающие **новый объект `Student`**, не изменяя текущий объект.
Необходимо реализовать:
```java
withGroupNumber(String groupNumber)
withAverageGrade(double averageGrade)
withRecordBookNumber(int recordBookNumber)
```
Каждый метод должен:
1. Сохранять исходный объект без изменений.
2. Изменять только указанное поле в новом объекте.
3. Сохранять остальные поля исходного объекта.
4. Повторно применять все правила валидации.
5. Возвращать новый валидный объект `Student`.
Пример:
```java
Student updated = student.withAverageGrade(4.8);
```
После выполнения:
```text
student.getAverageGrade() == прежнее значение
updated.getAverageGrade() == 4.8
```
Если новое значение невалидно, метод должен выбросить исключение, а исходный объект не должен измениться.
---
# `StudentBuilder`
Обновить существующий `StudentBuilder` в соответствии с новой моделью `Student`.
Методы должны соответствовать типам:
```java
setGroupNumber(String groupNumber)
setAverageGrade(double averageGrade)
setRecordBookNumber(int recordBookNumber)
```
`build()` должен создавать только валидный `Student`.
Все новые правила валидации должны применяться при создании объекта через `StudentBuilder`.
---
# Обновление зависимого кода
Найти и обновить весь код, использующий `Student` и изменяемые методы или типы.
В частности, обновить:
- `Comparator<Student>`;
- сортировки;
- источники данных;
- тестовые классы;
- создание `Student`;
- `with...()`-операции;
- чтение и запись данных, если они используют `recordBookNumber`.
Например, существующий:
```java
implements Comparator<Student>
```
должен использовать актуальный метод:
```java
getAverageGrade()
```
вместо ошибочного `getAvarageGrade()`.
Компаратор `recordBookNumber` должен сравнивать значения как числа.
Например:
```java
Integer.compare(
s1.getRecordBookNumber(),
s2.getRecordBookNumber()
)
```
Все места, где `recordBookNumber` рассматривался как `String`, необходимо адаптировать к `int`.
---
# Тесты
Обновить существующий `StudentTest` с учётом новой модели.
## Создание корректного `Student`
Проверить создание объекта со значениями:
```text
groupNumber = A12
averageGrade = 4.5
recordBookNumber = 12345
```
Проверить корректность всех геттеров.
## Проверка `groupNumber`
Проверить успешное создание для:
```text
A12
B32
Z00
```
Проверить исключение для:
```text
a12
A1
A123
AA1
а1А
аа!!а123
23фи!12
№№###*()
```
## Проверка `averageGrade`
Проверить:
```text
0.0 — допустимо
5.0 — допустимо
-1.0 — недопустимо
6.0 — недопустимо
```
## Проверка `recordBookNumber`
Проверить:
```text
1 — допустимо
12345 — допустимо
0 — недопустимо
-1 — недопустимо
```
## Тесты `with...()`
### `withGroupNumber()`
Проверить, что:
- возвращается новый объект;
- `groupNumber` изменён;
- `averageGrade` не изменился;
- `recordBookNumber` не изменился;
- исходный `Student` остался прежним.
### `withAverageGrade()`
Проверить те же свойства для `averageGrade`.
### `withRecordBookNumber()`
Проверить те же свойства для `recordBookNumber`.
### `with...()` с невалидным значением
Для каждого метода передать некорректное значение.
Проверить:
- выбрасывается `IllegalArgumentException`;
- исходный объект не изменяется;
- не создаётся невалидный `Student`.
## `equals()` и `hashCode()`
Обновить существующие тесты с учётом `int recordBookNumber`.
Проверить:
- одинаковые студенты равны;
- одинаковые студенты имеют одинаковый `hashCode`;
- изменение любого поля создаёт отличающийся объект.
## Результат
Необходимо обновить:
```text
Student.java
StudentBuilder.java
StudentTest.java
```
а также **все классы проекта, зависящие от изменённого интерфейса `Student`**, включая компараторы и другие реализации, использующие `recordBookNumber`, `groupNumber`, `averageGrade` или их геттеры.
### Основной принцип
`Student` должен оставаться единственной точкой истины для валидности данных:
```text
StudentBuilder ──┐
├──> Student
with...() ───────┘
```
Ни `Builder`, ни `with...()`, ни внешние классы не должны позволять создать невалидный объект.