Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
c3fb9ce
Заменить часть циклов for на forEach или Stream
h0ttab Jun 22, 2025
d32756c
Добавить поля duration и startTime в класс Task
h0ttab Jun 22, 2025
0ac412a
Добавить вычисляемые поля в Epic
h0ttab Jun 22, 2025
6455d50
Добавить вычисляемые поля в Epic
h0ttab Jun 22, 2025
6a941cd
Хранить задачи и подзадачи в порядке приоритета
h0ttab Jun 22, 2025
7353c6a
Добавить проверку задач на пересечение
h0ttab Jun 22, 2025
363ff25
Обновить toString(), hashCode(), equals() у классов задач
h0ttab Jun 22, 2025
d409916
Обновить методы сохранения/загрузки из CSV
h0ttab Jun 22, 2025
fa70f19
Обновить и пофиксить имитацию пользовательских сценариев
h0ttab Jun 22, 2025
2c3fe8c
Алгоритм поиска пересечений улучшен до O(log(n))
h0ttab Jun 22, 2025
a8b79d4
Алгоритм поиска пересечений улучшен до O(log(n))
h0ttab Jun 22, 2025
67571bc
Возвращать Optional в методах поиска задач и подзадач
h0ttab Jun 23, 2025
2b52421
Исправлены старые тесты класса Task
h0ttab Jun 23, 2025
97c6a05
Исправлены старые тесты класса SubTask
h0ttab Jun 23, 2025
2f65473
Обновить старые тесты класса Task
h0ttab Jun 23, 2025
053b567
Обновить старые тесты класса SubTask
h0ttab Jun 23, 2025
42113d8
Обновить старые тесты класса Epic
h0ttab Jun 23, 2025
02f6aaa
Code style
h0ttab Jun 23, 2025
ea66c33
Добавить константы тестовых значений для Duration/LocalDateTime
h0ttab Jun 23, 2025
f56bbc6
Исправить и обновить старые тесты класса InMemoryTaskManager
h0ttab Jun 23, 2025
f6d449c
Исправить и обновить старые тесты класса Managers
h0ttab Jun 23, 2025
62622e2
Исправить и обновить старые тесты класса FileBackedTaskManager
h0ttab Jun 23, 2025
3f28e87
Исправить и обновить старые тесты класса InMemoryHistoryManager
h0ttab Jun 23, 2025
5c66a6f
Добавить новые тесты в EpicTest
h0ttab Jun 23, 2025
590636c
Добавить новые тесты в TaskTest
h0ttab Jun 23, 2025
d92056f
Добавить новые тесты в EpicTest
h0ttab Jun 23, 2025
163fb89
Рефакторинг тестов
h0ttab Jun 23, 2025
be9e42f
Добавить новыйт тест в InMemoryHistoryManagerTest
h0ttab Jun 23, 2025
10b89a2
Исправить расчёт продолжительности эпика
h0ttab Jun 23, 2025
91ebf13
Исправить тип возвращаемого значения в Managers.getDefault
h0ttab Jun 24, 2025
a3a6c33
Исправить ошибку обнаружения ложного пересечения при обновлении задач…
h0ttab Jun 24, 2025
cfd684c
Добавить обновление вычисляемых полей эпика при выгрузке в CSV
h0ttab Jun 24, 2025
103c13e
Вынести общие тесты TaskManager в абстрактный класс
h0ttab Jun 24, 2025
6d4b85a
Code style
h0ttab Jun 24, 2025
edd4522
Добавить тест на проверку пересечений времени задач
h0ttab Jun 24, 2025
0b745be
Добавить механизм распределения освободившихся ID
h0ttab Jun 24, 2025
15b481c
Рефакторинг методов удаления задач/подзадач по ID
h0ttab Jun 24, 2025
c47d4fb
CodeStyle + Refactor
h0ttab Jun 24, 2025
376ad66
Добавить расчёт вычисляемых полей эпиков после загрузки из файла
h0ttab Jun 24, 2025
b5e7935
Code style
h0ttab Jun 24, 2025
ba161e4
Обновить демонстрационные сценарии
h0ttab Jun 24, 2025
da7b4ed
Code style
h0ttab Jun 24, 2025
760c55d
Добавить проверку на корректное разделение задач по приоритету
h0ttab Jun 24, 2025
7ac0841
Refactor
h0ttab Jun 24, 2025
4e00560
Refactor
h0ttab Jun 24, 2025
b3ad7e0
Refactor
h0ttab Jun 24, 2025
d294ec9
Реализовать toString() у классов задач через String.format
h0ttab Jun 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions src/app/Main.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package app;

import java.time.Duration;
import java.time.LocalDateTime;

import model.*;
import service.Managers;
import service.TaskManager;
Expand Down Expand Up @@ -42,16 +45,21 @@ public static void main(String[] args) {
private static TaskManager getTaskManager() {
TaskManager manager = Managers.getDefault();

Task taskA = new Task("Задача A", "Описание задачи A", Status.NEW);
Task taskB = new Task("Задача B", "Описание задачи B", Status.DONE);
LocalDateTime testDateTime = LocalDateTime.now();
Duration testDuration = Duration.ofMinutes(30);

Task taskA = new Task("Задача A", "Описание задачи A", Status.NEW,
testDuration, testDateTime);
Task taskB = new Task("Задача B", "Описание задачи B", Status.DONE,
testDuration, testDateTime.plus(Duration.ofHours(1)));
Epic epicA = new Epic("Эпик A", "Описание эпика с тремя подзадачами");
Epic epicB = new Epic("Эпик B", "Описание эпика без подзадач");
SubTask subTaskA = new SubTask("Подзадача A1", "Подзадача 1 эпика A",
Status.NEW, 3);
Status.NEW, 3, testDuration, testDateTime.plus(Duration.ofHours(2)));
SubTask subTaskB = new SubTask("Подзадача A2", "Подзадача 2 эпика A",
Status.DONE, 3);
Status.DONE, 3, testDuration, testDateTime.plus(Duration.ofHours(3)));
SubTask subTaskC = new SubTask("Подзадача A3", "Подзадача 3 эпика A",
Status.NEW, 3);
Status.NEW, 3, testDuration, testDateTime.plus(Duration.ofHours(4)));

manager.createTask(taskA); // id = 1
manager.createTask(taskB); // id = 2
Expand All @@ -66,9 +74,7 @@ private static TaskManager getTaskManager() {
private static void printAllTasks(TaskManager manager) {
System.out.println();
System.out.println("Задачи:");
for (Task task : manager.getTasks()) {
System.out.println(task);
}
manager.getTasks().forEach(System.out::println);
System.out.println();

System.out.println("Эпики:");
Expand All @@ -82,15 +88,11 @@ private static void printAllTasks(TaskManager manager) {
System.out.println();

System.out.println("Подзадачи:");
for (Task subtask : manager.getSubTasks()) {
System.out.println(subtask);
}
manager.getSubTasks().forEach(System.out::println);
System.out.println();

System.out.println("История:");
for (Task task : manager.getHistory()) {
System.out.println(task);
}
manager.getHistory().forEach(System.out::println);
System.out.println();
}
}
65 changes: 58 additions & 7 deletions src/model/Epic.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package model;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

public class Epic extends Task {
private Map<Integer, Status> relatedSubTaskMap;
private LocalDateTime endTime;

public Epic(String title, String description) {
super(title, description, Status.NEW);
Expand Down Expand Up @@ -59,6 +63,33 @@ public void updateSubTask(SubTask subTask) {
}
}

public void updateTimeFrame(TreeSet<SubTask> sortedSubTasks) {
TreeSet<SubTask> allSubTasks = sortedSubTasks;

Duration totalDuration = Duration.ofMinutes(
allSubTasks.stream()
.reduce(
0L,
(subtotal, subTask) -> subtotal + subTask.getDuration().toMinutes(), Long::sum)
);

allSubTasks = sortedSubTasks.stream()
.filter(s -> s.getStartTime().isPresent())
.collect(Collectors.toCollection(TreeSet::new));

LocalDateTime startTime;
if (allSubTasks.isEmpty()) {
startTime = null;
setEndTime(null);
} else {
startTime = allSubTasks.getFirst().getStartTime().get();
SubTask lastSubTask = allSubTasks.getLast();
setEndTime(lastSubTask.getStartTime().get().plus(lastSubTask.getDuration()));
}
setStartTime(startTime);
setDuration(totalDuration);
}

@Override
public Status getStatus() {
boolean isAllNew = true;
Expand Down Expand Up @@ -86,6 +117,15 @@ public Status getStatus() {
}
}

@Override
public Optional<LocalDateTime> getEndTime() {
return Optional.ofNullable(endTime);
}

public void setEndTime(LocalDateTime endTime) {
this.endTime = endTime;
}

@Override
public String toCSV(int headersCount) {
return super.toCSV(headersCount).replace("TASK", "EPIC");
Expand Down Expand Up @@ -114,12 +154,23 @@ public boolean equals(Object object) {

@Override
public String toString() {
return "Epic{" +
"subTaskIdList=" + getSubTaskIdList() +
", id=" + super.getId() +
", title='" + super.getTitle() + '\'' +
", description.length='" + super.getDescription().length() + '\'' +
", status=" + getStatus() +
'}';
String durationString;

try {
durationString = String.valueOf(super.getDuration().toMinutes());
} catch (NullPointerException e) {
durationString = "N/A";
}
return String.format("Epic{subTaskIdList=%s, id=%d, title='%s', description.length='%d', "
+ "status=%s, startTime=%s, duration=%s min, endTime=%s}",
getSubTaskIdList(),
super.getId(),
super.getTitle(),
super.getDescription().length(),
super.getStatus(),
super.getFormatterStartTime(),
durationString,
super.getFormattedEndTime()
);
}
}
33 changes: 25 additions & 8 deletions src/model/SubTask.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
package model;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Objects;

public class SubTask extends Task {
private final int epicId;

public SubTask(String title, String description, Status status, int epicId) {
protected SubTask(String title, String description, Status status, int epicId) {
super(title, description, status);
this.epicId = epicId;
}

public SubTask(String title, String description, Status status, int epicId, Duration duration) {
this(title, description, status, epicId);
super.setDuration(duration);
}

public SubTask(String title, String description, Status status, int epicId,
Duration duration, LocalDateTime startTime) {
this(title, description, status, epicId, duration);
super.setStartTime(startTime);
}

public int getEpicId() {
return epicId;
}
Expand Down Expand Up @@ -43,12 +56,16 @@ public boolean equals(Object object) {

@Override
public String toString() {
return "SubTask{" +
"epicId=" + getEpicId() +
", id=" + super.getId() +
", title='" + super.getTitle() + '\'' +
", description.length='" + super.getDescription().length() + '\'' +
", status=" + super.getStatus() +
'}';
return String.format("SubTask{epicId=%d, id=%d, title='%s', description.length='%d', "
+ "status=%s, startTime=%s, duration=%d min, endTime=%s}",
getEpicId(),
super.getId(),
super.getTitle(),
super.getDescription().length(),
super.getStatus(),
super.getFormatterStartTime(),
super.getDuration().toMinutes(),
super.getFormattedEndTime()
);
}
}
113 changes: 103 additions & 10 deletions src/model/Task.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
package model;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Optional;

public class Task {
import service.utils.Utils;

public class Task implements Comparable<Task> {
private final String title;
private final String description;
private final Status status;
private Duration duration;
private LocalDateTime startTime;
private int id;

public Task(String title, String description, Status status) {
protected Task(String title, String description, Status status) {
this.title = title;
this.description = description;
this.status = status;
}

public Task(String title, String description, Status status, Duration duration) {
this(title, description, status);
this.duration = duration;
}

public Task(String title, String description, Status status, Duration duration, LocalDateTime startTime) {
this(title, description, status, duration);
this.startTime = startTime;
}

public int getId() {
return id;
}
Expand All @@ -34,13 +51,82 @@ public Status getStatus() {
return status;
}

public Optional<LocalDateTime> getEndTime() {
return Optional.ofNullable(startTime).map(time -> time.plus(duration));
}

public Duration getDuration() {
return duration;
}

protected void setDuration(Duration duration) {
this.duration = duration;
}

public Optional<LocalDateTime> getStartTime() {
return Optional.ofNullable(startTime);
}

public void setStartTime(LocalDateTime startTime) {
this.startTime = startTime;
}

protected String getFormatterStartTime() {
String startTimeString = "N/A";

if (getStartTime().isPresent()) {
startTimeString = getStartTime().get().format(Utils.formatter);
}

return startTimeString;
}

protected String getFormattedEndTime() {
String endTimeString = "N/A";

if (getEndTime().isPresent()) {
endTimeString = getEndTime().get().format(Utils.formatter);
}

return endTimeString;
}

public String toCSV(int headersCount) {
return String.format("%s,%s,%s,%s,%s", id, "TASK", title, status, description);
String duration;
try {
duration = String.valueOf(getDuration().toMinutes());
} catch (NullPointerException e) {
duration = "0";
}
return String.format("%s,%s,%s,%s,%s,%s,%s",
id, "TASK", title, status, description,
getFormatterStartTime(), duration);
}

@Override
public int compareTo(Task task) {
Optional<LocalDateTime> timeA = this.getStartTime();
Optional<LocalDateTime> timeB = task.getStartTime();

if (timeA.isEmpty() && timeB.isEmpty()) {
return 0;
}

if (timeA.isPresent() && timeB.isEmpty()) {
return -1;
}

if (timeA.isEmpty()) {
return 1;
}

return timeA.get().compareTo(timeB.get());
}

@Override
public int hashCode() {
return Objects.hash(getId(), getTitle(), getDescription(), getStatus());
return Objects.hash(getId(), getTitle(), getDescription(),
getStatus(), getStartTime(), getDuration(), getEndTime());
}

@Override
Expand All @@ -59,16 +145,23 @@ public boolean equals(Object object) {
return (this.id == task.id
&& Objects.equals(this.title, task.title)
&& Objects.equals(this.description, task.description)
&& Objects.equals(this.getStartTime(), task.getStartTime())
&& Objects.equals(this.duration, task.getDuration())
&& Objects.equals(this.getEndTime(), task.getEndTime())
&& this.getStatus() == task.getStatus());
}

@Override
public String toString() {
return "Task{" +
"id=" + getId() +
", title='" + getTitle() + '\'' +
", description.length='" + getDescription().length() + '\'' +
", status=" + getStatus() +
'}';
return String.format("Task{id=%d, title='%s', description.length='%d', "
+ "status=%s, startTime=%s, duration=%d min, endTime=%s}",
getId(),
getTitle(),
getDescription().length(),
getStatus(),
getFormatterStartTime(),
getDuration().toMinutes(),
getFormattedEndTime()
);
}
}
Loading