From 2cf2b6ad3883f8d8ef27cf868265bc25df5f97b9 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Sat, 11 Apr 2026 22:19:27 +0300 Subject: [PATCH 01/19] feat: add FileBackedTaskManager class --- .idea/checkstyle-idea.xml | 16 ++++++++++++++++ src/service/FileBackedTaskManager.java | 11 +++++++++++ 2 files changed, 27 insertions(+) create mode 100644 .idea/checkstyle-idea.xml create mode 100644 src/service/FileBackedTaskManager.java diff --git a/.idea/checkstyle-idea.xml b/.idea/checkstyle-idea.xml new file mode 100644 index 0000000..742470c --- /dev/null +++ b/.idea/checkstyle-idea.xml @@ -0,0 +1,16 @@ + + + + 13.3.0 + JavaOnly + true + + + \ No newline at end of file diff --git a/src/service/FileBackedTaskManager.java b/src/service/FileBackedTaskManager.java new file mode 100644 index 0000000..849c467 --- /dev/null +++ b/src/service/FileBackedTaskManager.java @@ -0,0 +1,11 @@ +package service; + +import java.io.File; + +public class FileBackedTaskManager extends InMemoryTaskManager { + private final File file; + + public FileBackedTaskManager(File file) { + this.file = file; + } +} From 86b3d83b6c454eb6159342474bb6dd8f70f04943 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 13:57:32 +0300 Subject: [PATCH 02/19] feat: add TaskType enum --- src/model/TaskType.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/model/TaskType.java diff --git a/src/model/TaskType.java b/src/model/TaskType.java new file mode 100644 index 0000000..3e5d34b --- /dev/null +++ b/src/model/TaskType.java @@ -0,0 +1,7 @@ +package model; + +public enum TaskType { + TASK, + EPIC, + SUBTASK +} From 738124f4c0e11fdd1ead6a665331ad8f24f62733 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 14:02:44 +0300 Subject: [PATCH 03/19] feat: add ManagerSaveException class --- java-kanban.iml | 3 +++ src/service/ManagerSaveException.java | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 src/service/ManagerSaveException.java diff --git a/java-kanban.iml b/java-kanban.iml index 66c15d2..019c6c8 100644 --- a/java-kanban.iml +++ b/java-kanban.iml @@ -1,5 +1,8 @@ + + diff --git a/src/service/ManagerSaveException.java b/src/service/ManagerSaveException.java new file mode 100644 index 0000000..40b42b4 --- /dev/null +++ b/src/service/ManagerSaveException.java @@ -0,0 +1,11 @@ +package service; + +public class ManagerSaveException extends RuntimeException { + public ManagerSaveException(String message) { + super(message); + } + + public ManagerSaveException(String message, Throwable cause) { + super(message, cause); + } +} From 499dd072400138e67030ade8993916b2fc9cd9c3 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 14:26:16 +0300 Subject: [PATCH 04/19] feat: implement save logic in FileBackedTaskManager --- src/service/FileBackedTaskManager.java | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/service/FileBackedTaskManager.java b/src/service/FileBackedTaskManager.java index 849c467..5c85ccd 100644 --- a/src/service/FileBackedTaskManager.java +++ b/src/service/FileBackedTaskManager.java @@ -1,6 +1,15 @@ package service; +import model.Epic; +import model.Subtask; +import model.Task; +import model.TaskType; + +import java.io.BufferedWriter; import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.TreeMap; public class FileBackedTaskManager extends InMemoryTaskManager { private final File file; @@ -8,4 +17,57 @@ public class FileBackedTaskManager extends InMemoryTaskManager { public FileBackedTaskManager(File file) { this.file = file; } + + public void save() { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { + writer.write("id,type,name,status,description,epic"); + writer.newLine(); + + TreeMap allTasks = new TreeMap<>(); + + for (Task task : getTasks()) { + allTasks.put(task.getId(), task); + } + + for (Epic epic : getEpics()) { + allTasks.put(epic.getId(), epic); + } + + for (Subtask subtask : getSubtasks()) { + allTasks.put(subtask.getId(), subtask); + } + + for (Task task : allTasks.values()) { + writer.write(toString(task)); + writer.newLine(); + } + } catch (IOException e) { + throw new ManagerSaveException("Failed to save tasks to file: " + file, e); + } + } + + private String toString(Task task) { + StringBuilder builder = new StringBuilder(); + + builder.append(task.getId()).append(","); + + if (task instanceof Subtask) { + builder.append(TaskType.SUBTASK).append(","); + } else if (task instanceof Epic) { + builder.append(TaskType.EPIC).append(","); + } else { + builder.append(TaskType.TASK).append(","); + } + + builder.append(task.getName()).append(","); + builder.append(task.getStatus()).append(","); + builder.append(task.getDescription()).append(","); + + if (task instanceof Subtask) { + Subtask subtask = (Subtask) task; + builder.append(subtask.getEpicId()); + } + + return builder.toString(); + } } From fdf7aa5c6a487c757b74cc1e15ee112cb75c381c Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 14:43:31 +0300 Subject: [PATCH 05/19] feat: add autosave after task manager mutations --- src/service/FileBackedTaskManager.java | 78 ++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/service/FileBackedTaskManager.java b/src/service/FileBackedTaskManager.java index 5c85ccd..a788917 100644 --- a/src/service/FileBackedTaskManager.java +++ b/src/service/FileBackedTaskManager.java @@ -18,6 +18,7 @@ public FileBackedTaskManager(File file) { this.file = file; } + // Сохраняет текущее состояние менеджера в CSV-файл public void save() { try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { writer.write("id,type,name,status,description,epic"); @@ -46,6 +47,7 @@ public void save() { } } + // Преобразует задачу в строку формата CSV private String toString(Task task) { StringBuilder builder = new StringBuilder(); @@ -70,4 +72,80 @@ private String toString(Task task) { return builder.toString(); } + + // После каждого изменения сохраняем состояние менеджера в файл + @Override + public void clearTasks() { + super.clearTasks(); + save(); + } + + @Override + public void clearEpics() { + super.clearEpics(); + save(); + } + + @Override + public void clearSubtasks() { + super.clearSubtasks(); + save(); + } + + @Override + public Task createTask(Task task) { + Task createdTask = super.createTask(task); + save(); + return createdTask; + } + + @Override + public Epic createEpic(Epic epic) { + Epic createdEpic = super.createEpic(epic); + save(); + return createdEpic; + } + + @Override + public Subtask createSubtask(Subtask subtask) { + Subtask createdSubtask = super.createSubtask(subtask); + save(); + return createdSubtask; + } + + @Override + public void updateTask(Task task) { + super.updateTask(task); + save(); + } + + @Override + public void updateEpic(Epic epic) { + super.updateEpic(epic); + save(); + } + + @Override + public void updateSubtask(Subtask subtask) { + super.updateSubtask(subtask); + save(); + } + + @Override + public void deleteTask(int id) { + super.deleteTask(id); + save(); + } + + @Override + public void deleteEpic(int id) { + super.deleteEpic(id); + save(); + } + + @Override + public void deleteSubtask(int id) { + super.deleteSubtask(id); + save(); + } } From ff4cad393433be50281a70d1717e7795919344a4 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 15:09:54 +0300 Subject: [PATCH 06/19] refactor: add protected methods for file loading support --- src/service/InMemoryTaskManager.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/service/InMemoryTaskManager.java b/src/service/InMemoryTaskManager.java index 1c4e95a..1935a45 100644 --- a/src/service/InMemoryTaskManager.java +++ b/src/service/InMemoryTaskManager.java @@ -276,4 +276,26 @@ public ArrayList getEpicSubtasks(int epicId) { } return result; } + + // Служебные методы для восстановления менеджера из файла + protected void putLoadedTask(Task task) { + tasks.put(task.getId(), task); + } + + protected void putLoadedEpic(Epic epic) { + epics.put(epic.getId(), epic); + } + + protected void putLoadedSubtask(Subtask subtask) { + subtasks.put(subtask.getId(), subtask); + + Epic epic = epics.get(subtask.getEpicId()); + if (epic != null) { + epic.addSubtaskId(subtask.getId()); + } + } + + protected void setNextId(int nextId) { + this.nextId = nextId; + } } From 8aa03824b97631f1bd778e81f1cb5211e2e83028 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 15:36:07 +0300 Subject: [PATCH 07/19] feat: add fromString method for CSV parsing --- src/service/FileBackedTaskManager.java | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/service/FileBackedTaskManager.java b/src/service/FileBackedTaskManager.java index a788917..862b6b5 100644 --- a/src/service/FileBackedTaskManager.java +++ b/src/service/FileBackedTaskManager.java @@ -1,6 +1,7 @@ package service; import model.Epic; +import model.Status; import model.Subtask; import model.Task; import model.TaskType; @@ -73,6 +74,32 @@ private String toString(Task task) { return builder.toString(); } + // Преобразует строку CSV в объект задачи + private static Task fromString(String value) { + String[] fields = value.split(",", -1); + + int id = Integer.parseInt(fields[0]); + TaskType taskType = TaskType.valueOf(fields[1]); + String name = fields[2]; + Status status = Status.valueOf(fields[3]); + String description = fields[4]; + + Task task; + + if (taskType == TaskType.TASK) { + task = new Task(name, description, status); + } else if (taskType == TaskType.EPIC) { + task = new Epic(name, description); + task.setStatus(status); + } else { + int epicId = Integer.parseInt(fields[5]); + task = new Subtask(name, description, status, epicId); + } + + task.setId(id); + return task; + } + // После каждого изменения сохраняем состояние менеджера в файл @Override public void clearTasks() { From b83adc936bc58c22e54fbabdb7f51c0141ff7e58 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 15:50:07 +0300 Subject: [PATCH 08/19] feat: add loadFromFile method to FileBackedTaskManager --- src/service/FileBackedTaskManager.java | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/service/FileBackedTaskManager.java b/src/service/FileBackedTaskManager.java index 862b6b5..f716bdf 100644 --- a/src/service/FileBackedTaskManager.java +++ b/src/service/FileBackedTaskManager.java @@ -6,8 +6,10 @@ import model.Task; import model.TaskType; +import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.TreeMap; @@ -100,6 +102,41 @@ private static Task fromString(String value) { return task; } + // Восстанавливает менеджер из CSV-файла + public static FileBackedTaskManager loadFromFile(File file) { + FileBackedTaskManager manager = new FileBackedTaskManager(file); + int maxId = 0; + + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line = reader.readLine(); // пропуск заголовка + + while ((line = reader.readLine()) != null) { + if (line.isBlank()) { + continue; + } + + Task task = fromString(line); + + if (task instanceof Subtask) { + manager.putLoadedSubtask((Subtask) task); + } else if (task instanceof Epic) { + manager.putLoadedEpic((Epic) task); + } else { + manager.putLoadedTask(task); + } + + if (task.getId() > maxId) { + maxId = task.getId(); + } + } + + manager.setNextId(maxId + 1); + return manager; + } catch (IOException e) { + throw new ManagerSaveException("Failed to load tasks from file: " + file, e); + } + } + // После каждого изменения сохраняем состояние менеджера в файл @Override public void clearTasks() { From 36824d8601d28b728973a52540dd51ae8df2c528 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 15:55:28 +0300 Subject: [PATCH 09/19] fix: recalculate epic statuses after loading from file --- src/service/FileBackedTaskManager.java | 4 ++++ src/service/InMemoryTaskManager.java | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/service/FileBackedTaskManager.java b/src/service/FileBackedTaskManager.java index f716bdf..8b26fcc 100644 --- a/src/service/FileBackedTaskManager.java +++ b/src/service/FileBackedTaskManager.java @@ -130,6 +130,10 @@ public static FileBackedTaskManager loadFromFile(File file) { } } + for (Epic epic : manager.getLoadedEpics()) { + manager.updateEpicStatus(epic); + } + manager.setNextId(maxId + 1); return manager; } catch (IOException e) { diff --git a/src/service/InMemoryTaskManager.java b/src/service/InMemoryTaskManager.java index 1935a45..b2d6126 100644 --- a/src/service/InMemoryTaskManager.java +++ b/src/service/InMemoryTaskManager.java @@ -191,7 +191,7 @@ public void updateEpic(Epic epic) { } // Метод для обновления статуса Эпик при обновлении Подзадач - private void updateEpicStatus(Epic epic) { + protected void updateEpicStatus(Epic epic) { if (epic.getSubtaskIds().isEmpty()) { epic.setStatus(Status.NEW); return; @@ -298,4 +298,8 @@ protected void putLoadedSubtask(Subtask subtask) { protected void setNextId(int nextId) { this.nextId = nextId; } + + protected ArrayList getLoadedEpics() { + return new ArrayList<>(epics.values()); + } } From 0dea6e62b7dd90460328f6fb6667a174aae6f03e Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 16:02:51 +0300 Subject: [PATCH 10/19] test: add test for saving and loading empty manager --- test/service/FileBackedTaskManagerTest.java | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/service/FileBackedTaskManagerTest.java diff --git a/test/service/FileBackedTaskManagerTest.java b/test/service/FileBackedTaskManagerTest.java new file mode 100644 index 0000000..d0a0401 --- /dev/null +++ b/test/service/FileBackedTaskManagerTest.java @@ -0,0 +1,32 @@ +package service; + +import model.Epic; +import model.Status; +import model.Subtask; +import model.Task; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +class FileBackedTaskManagerTest { + + // Тест на сохранение и загрузку пустого менеджера + @Test + void shouldSaveAndLoadEmptyManager() throws IOException { + File tempFile = File.createTempFile("tasks", ".csv"); + + FileBackedTaskManager manager = new FileBackedTaskManager(tempFile); + manager.save(); + + FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(tempFile); + + assertTrue(loadedManager.getTasks().isEmpty(), "Список задач должен быть пустым"); + assertTrue(loadedManager.getEpics().isEmpty(), "Список эпиков должен быть пустым"); + assertTrue(loadedManager.getSubtasks().isEmpty(), "Список подзадач должен быть пустым"); + } + + +} From 6cb7f308776494449a5873b5e6beafa3b14fcb83 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 16:08:19 +0300 Subject: [PATCH 11/19] test: add test for saving multiple tasks --- test/service/FileBackedTaskManagerTest.java | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/service/FileBackedTaskManagerTest.java b/test/service/FileBackedTaskManagerTest.java index d0a0401..d4d5b68 100644 --- a/test/service/FileBackedTaskManagerTest.java +++ b/test/service/FileBackedTaskManagerTest.java @@ -28,5 +28,28 @@ void shouldSaveAndLoadEmptyManager() throws IOException { assertTrue(loadedManager.getSubtasks().isEmpty(), "Список подзадач должен быть пустым"); } + // Тест на сохранение нескольких задач + @Test + void shouldSaveMultipleTasks() throws IOException { + File tempFile = File.createTempFile("tasks", ".csv"); + + FileBackedTaskManager manager = new FileBackedTaskManager(tempFile); + + Task task = new Task("Task1", "Description1", Status.NEW); + manager.createTask(task); + + Epic epic = new Epic("Epic1", "Description epic"); + manager.createEpic(epic); + Subtask subtask = new Subtask("Subtask1", "Description sub", Status.NEW, epic.getId()); + manager.createSubtask(subtask); + + manager.save(); + + FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(tempFile); + + assertEquals(1, loadedManager.getTasks().size(), "Должна быть 1 задача"); + assertEquals(1, loadedManager.getEpics().size(), "Должен быть 1 эпик"); + assertEquals(1, loadedManager.getSubtasks().size(), "Должна быть 1 подзадача"); + } } From 93c0b5cdd6864ca99311a23c4c9e6787bc02873c Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 16:21:13 +0300 Subject: [PATCH 12/19] test: add test for loading multiple tasks --- test/service/FileBackedTaskManagerTest.java | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/service/FileBackedTaskManagerTest.java b/test/service/FileBackedTaskManagerTest.java index d4d5b68..2e6cd27 100644 --- a/test/service/FileBackedTaskManagerTest.java +++ b/test/service/FileBackedTaskManagerTest.java @@ -52,4 +52,41 @@ void shouldSaveMultipleTasks() throws IOException { assertEquals(1, loadedManager.getEpics().size(), "Должен быть 1 эпик"); assertEquals(1, loadedManager.getSubtasks().size(), "Должна быть 1 подзадача"); } + + // Тест на загрузку нескольких задач из файла + @Test + void shouldLoadMultipleTasks() throws IOException { + File tempFile = File.createTempFile("tasks", ".csv"); + + FileBackedTaskManager manager = new FileBackedTaskManager(tempFile); + + Task task = new Task("Task1", "Description1", Status.NEW); + manager.createTask(task); + + Epic epic = new Epic("Epic1", "Description epic"); + manager.createEpic(epic); + + Subtask subtask = new Subtask("Subtask1", "Description sub", Status.DONE, epic.getId()); + manager.createSubtask(subtask); + manager.updateSubtask(subtask); + + FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(tempFile); + + Task loadedTask = loadedManager.getTasks().get(0); + Epic loadedEpic = loadedManager.getEpics().get(0); + Subtask loadedSubtask = loadedManager.getSubtasks().get(0); + + assertEquals("Task1", loadedTask.getName(), "Имя задачи должно совпадать"); + assertEquals("Description1", loadedTask.getDescription(), "Описание задачи должно совпадать"); + assertEquals(Status.NEW, loadedTask.getStatus(), "Статус задачи должен совпадать"); + + assertEquals("Epic1", loadedEpic.getName(), "Имя эпика должно совпадать"); + assertEquals("Description epic", loadedEpic.getDescription(), "Описание эпика должно совпадать"); + assertEquals(Status.DONE, loadedEpic.getStatus(), "Статус эпика должен пересчитаться по подзадаче"); + + assertEquals("Subtask1", loadedSubtask.getName(), "Имя подзадачи должно совпадать"); + assertEquals("Description sub", loadedSubtask.getDescription(), "Описание подзадачи должно совпадать"); + assertEquals(Status.DONE, loadedSubtask.getStatus(), "Статус подзадачи должен совпадать"); + assertEquals(epic.getId(), loadedSubtask.getEpicId(), "Epic ID подзадачи должен совпадать"); + } } From bf162d19c4ed3eb1b755a4ef2c661ff8fe9ba494 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 16:35:36 +0300 Subject: [PATCH 13/19] feat: add demo main method in FileBackedTaskManager for file persistence scenario --- src/service/FileBackedTaskManager.java | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/service/FileBackedTaskManager.java b/src/service/FileBackedTaskManager.java index 8b26fcc..11b9fbf 100644 --- a/src/service/FileBackedTaskManager.java +++ b/src/service/FileBackedTaskManager.java @@ -216,4 +216,59 @@ public void deleteSubtask(int id) { super.deleteSubtask(id); save(); } + + // Демонстрационный сценарий работы файлового менеджера + public static void main(String[] args) { + File file = new File("tasks.csv"); + + FileBackedTaskManager manager = new FileBackedTaskManager(file); + + // Создание обычных задач + Task task1 = new Task("Task1", "Description of task 1", Status.NEW); + Task task2 = new Task("Task2", "Description of task 2", Status.NEW); + manager.createTask(task1); + manager.createTask(task2); + + // Создание эпика + Epic epic1 = new Epic("Epic1", "Description of epic 1"); + manager.createEpic(epic1); + + // Создание подзадач для эпика + Subtask subtask1 = new Subtask("Subtask1", "Description of subtask 1", Status.NEW, epic1.getId()); + Subtask subtask2 = new Subtask("Subtask2", "Description of subtask 2", Status.NEW, epic1.getId()); + manager.createSubtask(subtask1); + manager.createSubtask(subtask2); + + // Меняем статус одной подзадачи для проверки пересчёта эпика + subtask1.setStatus(Status.DONE); + manager.updateSubtask(subtask1); + + // Загрузка нового менеджера из того же файла + FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(file); + + // Вывод данных из нового менеджера + System.out.println("Обычные задачи из загруженного менеджера:"); + for (Task task : loadedManager.getTasks()) { + System.out.println(task); + } + + System.out.println("Эпики из загруженного менеджера:"); + for (Epic epic : loadedManager.getEpics()) { + System.out.println(epic); + } + + System.out.println("Подзадачи из загруженного менеджера:"); + for (Subtask subtask : loadedManager.getSubtasks()) { + System.out.println(subtask); + } + + // Проверка, что данные действительно загрузились + if (loadedManager.getTasks().size() == manager.getTasks().size() + && loadedManager.getEpics().size() == manager.getEpics().size() + && loadedManager.getSubtasks().size() == manager.getSubtasks().size()) { + System.out.println("Данные успешно сохранены и загружены."); + } else { + System.out.println("Ошибка: данные после загрузки не совпадают."); + } + } } From 9bbd9f85db708c8a330cb71924894337c10875fe Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 16:52:33 +0300 Subject: [PATCH 14/19] test: fix loading test for FileBackedTaskManager --- test/service/FileBackedTaskManagerTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/service/FileBackedTaskManagerTest.java b/test/service/FileBackedTaskManagerTest.java index 2e6cd27..81713d3 100644 --- a/test/service/FileBackedTaskManagerTest.java +++ b/test/service/FileBackedTaskManagerTest.java @@ -44,8 +44,6 @@ void shouldSaveMultipleTasks() throws IOException { Subtask subtask = new Subtask("Subtask1", "Description sub", Status.NEW, epic.getId()); manager.createSubtask(subtask); - manager.save(); - FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(tempFile); assertEquals(1, loadedManager.getTasks().size(), "Должна быть 1 задача"); @@ -66,8 +64,10 @@ void shouldLoadMultipleTasks() throws IOException { Epic epic = new Epic("Epic1", "Description epic"); manager.createEpic(epic); - Subtask subtask = new Subtask("Subtask1", "Description sub", Status.DONE, epic.getId()); + Subtask subtask = new Subtask("Subtask1", "Description sub", Status.NEW, epic.getId()); manager.createSubtask(subtask); + + subtask.setStatus(Status.DONE); manager.updateSubtask(subtask); FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(tempFile); @@ -88,5 +88,9 @@ void shouldLoadMultipleTasks() throws IOException { assertEquals("Description sub", loadedSubtask.getDescription(), "Описание подзадачи должно совпадать"); assertEquals(Status.DONE, loadedSubtask.getStatus(), "Статус подзадачи должен совпадать"); assertEquals(epic.getId(), loadedSubtask.getEpicId(), "Epic ID подзадачи должен совпадать"); + + assertEquals(task.getId(), loadedTask.getId(), "ID задачи должен совпадать"); + assertEquals(epic.getId(), loadedEpic.getId(), "ID эпика должен совпадать"); + assertEquals(subtask.getId(), loadedSubtask.getId(), "ID подзадачи должен совпадать"); } } From ecaa5f24889bdb8d74362a981176ee595b2783f7 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Tue, 14 Apr 2026 17:05:19 +0300 Subject: [PATCH 15/19] docs: add author name to README --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 353a9b5..4559b5d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # java-kanban -Repository for homework project. + +Проект - Трекер задач. + +## Автор +Ксения \ No newline at end of file From 6d235809dabf3e95c42c88de505bebddcce2b786 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Wed, 15 Apr 2026 22:29:18 +0300 Subject: [PATCH 16/19] refactor: add getType method to task entities --- src/model/Epic.java | 7 ++++++- src/model/Subtask.java | 5 +++++ src/model/Task.java | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/model/Epic.java b/src/model/Epic.java index 00edfd5..2cd2cae 100644 --- a/src/model/Epic.java +++ b/src/model/Epic.java @@ -14,7 +14,7 @@ public ArrayList getSubtaskIds() { } public void setSubtaskIds(ArrayList subtaskIds) { - this.subtaskIds = subtaskIds; + this.subtaskIds = new ArrayList<>(subtaskIds); } // Очищение всех ID подзадач @@ -34,6 +34,11 @@ public void removeSubtaskId(Integer subtaskId) { subtaskIds.remove(subtaskId); } + @Override + public TaskType getType() { + return TaskType.EPIC; + } + @Override public String toString() { return "Epic{" + diff --git a/src/model/Subtask.java b/src/model/Subtask.java index 50b0071..e888412 100644 --- a/src/model/Subtask.java +++ b/src/model/Subtask.java @@ -21,6 +21,11 @@ public void setEpicId(int epicId) { this.epicId = epicId; } + @Override + public TaskType getType() { + return TaskType.SUBTASK; + } + @Override public void setId(int id) { if (id == this.getEpicId()) { diff --git a/src/model/Task.java b/src/model/Task.java index 8ed25ad..0e96c0f 100644 --- a/src/model/Task.java +++ b/src/model/Task.java @@ -14,6 +14,10 @@ public Task(String name, String description, Status status) { this.status = status; } + public TaskType getType() { + return TaskType.TASK; + } + public int getId() { return id; } From 4724fab000b821758b8ad066485bcb2b2278825e Mon Sep 17 00:00:00 2001 From: Ksenia Date: Wed, 15 Apr 2026 22:37:08 +0300 Subject: [PATCH 17/19] refactor: make save() private --- src/service/FileBackedTaskManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/FileBackedTaskManager.java b/src/service/FileBackedTaskManager.java index 11b9fbf..02e18ba 100644 --- a/src/service/FileBackedTaskManager.java +++ b/src/service/FileBackedTaskManager.java @@ -22,7 +22,7 @@ public FileBackedTaskManager(File file) { } // Сохраняет текущее состояние менеджера в CSV-файл - public void save() { + private void save() { try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { writer.write("id,type,name,status,description,epic"); writer.newLine(); From 9d98936b2dcae3faee073dcd1ed0150f7d2bb497 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Wed, 15 Apr 2026 22:37:19 +0300 Subject: [PATCH 18/19] test: update empty manager test after save encapsulation --- test/service/FileBackedTaskManagerTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/service/FileBackedTaskManagerTest.java b/test/service/FileBackedTaskManagerTest.java index 81713d3..2e2bbe1 100644 --- a/test/service/FileBackedTaskManagerTest.java +++ b/test/service/FileBackedTaskManagerTest.java @@ -6,7 +6,9 @@ import model.Task; import org.junit.jupiter.api.Test; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import static org.junit.jupiter.api.Assertions.*; @@ -18,8 +20,10 @@ class FileBackedTaskManagerTest { void shouldSaveAndLoadEmptyManager() throws IOException { File tempFile = File.createTempFile("tasks", ".csv"); - FileBackedTaskManager manager = new FileBackedTaskManager(tempFile); - manager.save(); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) { + writer.write("id,type,name,status,description,epic"); + writer.newLine(); + } FileBackedTaskManager loadedManager = FileBackedTaskManager.loadFromFile(tempFile); From bd5aaed599cb2506a952f0739dd34091acb9876b Mon Sep 17 00:00:00 2001 From: Ksenia Date: Wed, 15 Apr 2026 23:24:01 +0300 Subject: [PATCH 19/19] refactor: replace instanceof with getType in FileBackedTaskManager --- src/service/FileBackedTaskManager.java | 29 ++++++++++---------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/service/FileBackedTaskManager.java b/src/service/FileBackedTaskManager.java index 02e18ba..44e50ce 100644 --- a/src/service/FileBackedTaskManager.java +++ b/src/service/FileBackedTaskManager.java @@ -55,14 +55,7 @@ private String toString(Task task) { StringBuilder builder = new StringBuilder(); builder.append(task.getId()).append(","); - - if (task instanceof Subtask) { - builder.append(TaskType.SUBTASK).append(","); - } else if (task instanceof Epic) { - builder.append(TaskType.EPIC).append(","); - } else { - builder.append(TaskType.TASK).append(","); - } + builder.append(task.getType()).append(","); builder.append(task.getName()).append(","); builder.append(task.getStatus()).append(","); @@ -117,12 +110,16 @@ public static FileBackedTaskManager loadFromFile(File file) { Task task = fromString(line); - if (task instanceof Subtask) { - manager.putLoadedSubtask((Subtask) task); - } else if (task instanceof Epic) { - manager.putLoadedEpic((Epic) task); - } else { - manager.putLoadedTask(task); + switch (task.getType()) { + case TASK: + manager.putLoadedTask(task); + break; + case EPIC: + manager.putLoadedEpic((Epic) task); + break; + case SUBTASK: + manager.putLoadedSubtask((Subtask) task); + break; } if (task.getId() > maxId) { @@ -130,10 +127,6 @@ public static FileBackedTaskManager loadFromFile(File file) { } } - for (Epic epic : manager.getLoadedEpics()) { - manager.updateEpicStatus(epic); - } - manager.setNextId(maxId + 1); return manager; } catch (IOException e) {