Files
aston-team-project/docs/tasks/CompositeStudentSearch.md
T

456 lines
10 KiB
Markdown
Raw 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.
# Техническое задание: поиск студентов с использованием паттерна Компоновщик
## Задача
Реализовать механизм поиска студентов по диапазону значений с использованием паттерна **Компоновщик**.
Должны поддерживаться следующие критерии поиска:
- диапазон `groupNumber`;
- диапазон `averageGrade`;
- диапазон `recordBookNumber`.
Критерии должны поддерживать объединение в составной критерий.
Режим объединения критериев — **объединение (ИЛИ)** или **пересечение (И)** — задаётся в конструкторе основного класса.
---
# Названия классов и интерфейсов
## `StudentSearchCriteria`
Интерфейс отдельного критерия поиска.
### Контракт
```java
boolean matches(Student student);
```
Метод возвращает `true`, если студент соответствует критерию.
---
## `GroupNumberRangeCriteria`
Критерий поиска по диапазону `groupNumber`.
### Конструктор
```java
GroupNumberRangeCriteria(String min, String max);
```
### Метод
```java
boolean matches(Student student);
```
`groupNumber` имеет тип `String`, поэтому сравнение выполнять лексикографически.
Границы диапазона включаются.
---
## `AverageGradeRangeCriteria`
Критерий поиска по диапазону `averageGrade`.
### Конструктор
```java
AverageGradeRangeCriteria(double min, double max);
```
### Метод
```java
boolean matches(Student student);
```
Студент соответствует критерию, если:
```text
min <= averageGrade <= max
```
---
## `RecordBookNumberRangeCriteria`
Критерий поиска по диапазону `recordBookNumber`.
### Конструктор
```java
RecordBookNumberRangeCriteria(int min, int max);
```
### Метод
```java
boolean matches(Student student);
```
Студент соответствует критерию, если:
```text
min <= recordBookNumber <= max
```
---
# `CompositeStudentSearchCriteria`
Компоновщик критериев поиска.
Класс реализует:
```java
StudentSearchCriteria
```
и содержит другие реализации `StudentSearchCriteria`.
### Методы
```java
void add(StudentSearchCriteria criteria);
```
```java
void remove(StudentSearchCriteria criteria);
```
```java
boolean matches(Student student);
```
### Логика
`CompositeStudentSearchCriteria` должен поддерживать два режима:
```text
UNION — объединение условий, ИЛИ
INTERSECTION — пересечение условий, И
```
Режим должен задаваться при создании компоновщика:
```java
CompositeStudentSearchCriteria(
SearchOperation operation
);
```
где `SearchOperation` — перечисление:
```java
public enum SearchOperation {
UNION,
INTERSECTION
}
```
Для `UNION` студент подходит, если выполняется **хотя бы один** вложенный критерий.
Для `INTERSECTION` студент подходит, если выполняются **все** вложенные критерии.
---
# `StudentSearchService`
Основной класс поиска.
Он должен принимать интерфейс `StudentSearchCriteria`, а не конкретную реализацию критерия.
### Конструктор
```java
StudentSearchService(StudentSearchCriteria criteria);
```
### Метод
```java
MyList<Student> find(MyList<Student> students);
```
### Поведение
Метод `find()` должен:
1. Последовательно проверить студентов исходной коллекции.
2. Передать каждого студента в:
```java
criteria.matches(student)
```
1. Добавить подходящих студентов в новую `MyList<Student>`.
2. Вернуть новую коллекцию.
`StudentSearchService` не должен содержать логику конкретных диапазонов или объединения критериев.
### Обработка отсутствующего критерия
Если `StudentSearchService` создан без критерия:
```java
new StudentSearchService(null);
```
необходимо выбросить:
```java
IllegalArgumentException
```
Класс не должен выполнять поиск без заданного критерия.
---
# Пример использования
### Один критерий
```java
StudentSearchCriteria criteria =
new AverageGradeRangeCriteria(4.0, 5.0);
StudentSearchService service =
new StudentSearchService(criteria);
MyList<Student> result =
service.find(students);
```
### Пересечение критериев
Например, студент должен одновременно:
- находиться в группе от `A10` до `C30`;
- иметь средний балл от `4.0` до `5.0`.
```java
CompositeStudentSearchCriteria criteria =
new CompositeStudentSearchCriteria(
SearchOperation.INTERSECTION
);
criteria.add(
new GroupNumberRangeCriteria("A10", "C30")
);
criteria.add(
new AverageGradeRangeCriteria(4.0, 5.0)
);
StudentSearchService service =
new StudentSearchService(criteria);
```
### Объединение критериев
Студент должен соответствовать хотя бы одному условию:
```java
CompositeStudentSearchCriteria criteria =
new CompositeStudentSearchCriteria(
SearchOperation.UNION
);
criteria.add(
new AverageGradeRangeCriteria(4.5, 5.0)
);
criteria.add(
new RecordBookNumberRangeCriteria(10000, 20000)
);
StudentSearchService service =
new StudentSearchService(criteria);
```
---
# Общие требования
1. `StudentSearchService` должен работать только через `StudentSearchCriteria`.
2. `StudentSearchService` не должен знать о конкретных критериях.
3. `CompositeStudentSearchCriteria` должен реализовывать тот же интерфейс `StudentSearchCriteria`.
4. Должна поддерживаться вложенность компоновщиков.
Например:
```text
Composite
├── GroupNumberRangeCriteria
└── Composite
├── AverageGradeRangeCriteria
└── RecordBookNumberRangeCriteria
```
1. Исходную `MyList<Student>` не изменять.
2. Результат возвращать в виде новой `MyList<Student>`.
3. Порядок найденных студентов должен сохраняться.
4. Стандартные `List`, `ArrayList`, `LinkedList` не использовать.
5. Готовые методы поиска не использовать.
6. При отсутствии совпадений возвращать пустую `MyList<Student>`.
7. Для диапазонов `min > max` выбрасывать `IllegalArgumentException`.
---
# Примеры тестов
## `GroupNumberRangeCriteria`
Проверить:
- значение внутри диапазона;
- значение равное нижней границе;
- значение равное верхней границе;
- значение вне диапазона.
## `AverageGradeRangeCriteria`
Проверить:
```text
3.9 → false
4.0 → true
4.5 → true
5.0 → true
5.1 → false
```
## `RecordBookNumberRangeCriteria`
Проверить значения внутри и вне диапазона, включая обе границы.
## Некорректный диапазон
Для каждого критерия проверить:
```text
min > max
```
Ожидается:
```java
IllegalArgumentException
```
## `INTERSECTION`
Создать два критерия и проверить:
```text
критерий A = true
критерий B = true
→ true
```
```text
критерий A = true
критерий B = false
→ false
```
## `UNION`
Проверить:
```text
A = true
B = false
→ true
```
```text
A = false
B = true
→ true
```
```text
A = false
B = false
→ false
```
## Компоновщик без критериев
Проверить поведение:
```java
new CompositeStudentSearchCriteria(
SearchOperation.INTERSECTION
);
```
и:
```java
new CompositeStudentSearchCriteria(
SearchOperation.UNION
);
```
Поведение должно быть явно определено и закреплено тестами.
Рекомендуется:
- пустое `INTERSECTION` → `true`;
- пустое `UNION` → `false`.
## `StudentSearchService`
Проверить:
- корректный поиск по одному критерию;
- пустой результат;
- пустую исходную коллекцию;
- сохранение порядка;
- неизменность исходной коллекции;
- работу с `CompositeStudentSearchCriteria`.
## Проверка вложенного Компоновщика
Создать компоновщик с вложенным компоновщиком и проверить корректность вычисления результата.
## Проверка отсутствующего критерия
Создать:
```java
new StudentSearchService(null);
```
Проверить `IllegalArgumentException`.
## Результат
Реализовать:
```text
StudentSearchCriteria.java
GroupNumberRangeCriteria.java
AverageGradeRangeCriteria.java
RecordBookNumberRangeCriteria.java
CompositeStudentSearchCriteria.java
SearchOperation.java
StudentSearchService.java
```
## Git
Название ветки:
```text
feature/composite-student-search
```