-
Notifications
You must be signed in to change notification settings - Fork 0
Sprint 7 solution #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
2cf2b6a
feat: add FileBackedTaskManager class
ksupyl 86b3d83
feat: add TaskType enum
ksupyl 738124f
feat: add ManagerSaveException class
ksupyl 499dd07
feat: implement save logic in FileBackedTaskManager
ksupyl fdf7aa5
feat: add autosave after task manager mutations
ksupyl ff4cad3
refactor: add protected methods for file loading support
ksupyl 8aa0382
feat: add fromString method for CSV parsing
ksupyl b83adc9
feat: add loadFromFile method to FileBackedTaskManager
ksupyl 36824d8
fix: recalculate epic statuses after loading from file
ksupyl 0dea6e6
test: add test for saving and loading empty manager
ksupyl 6cb7f30
test: add test for saving multiple tasks
ksupyl 93c0b5c
test: add test for loading multiple tasks
ksupyl bf162d1
feat: add demo main method in FileBackedTaskManager for file persiste…
ksupyl 9bbd9f8
test: fix loading test for FileBackedTaskManager
ksupyl ecaa5f2
docs: add author name to README
ksupyl 6d23580
refactor: add getType method to task entities
ksupyl 4724fab
refactor: make save() private
ksupyl 9d98936
test: update empty manager test after save encapsulation
ksupyl bd5aaed
refactor: replace instanceof with getType in FileBackedTaskManager
ksupyl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,6 @@ | ||
| # java-kanban | ||
| Repository for homework project. | ||
|
|
||
| Проект - Трекер задач. | ||
|
|
||
| ## Автор | ||
| Ксения |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package model; | ||
|
|
||
| public enum TaskType { | ||
| TASK, | ||
| EPIC, | ||
| SUBTASK | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,267 @@ | ||
| package service; | ||
|
|
||
| import model.Epic; | ||
| import model.Status; | ||
| import model.Subtask; | ||
| 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; | ||
|
|
||
| public class FileBackedTaskManager extends InMemoryTaskManager { | ||
| private final File file; | ||
|
|
||
| public FileBackedTaskManager(File file) { | ||
| this.file = file; | ||
| } | ||
|
|
||
| // Сохраняет текущее состояние менеджера в CSV-файл | ||
| private void save() { | ||
| try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { | ||
| writer.write("id,type,name,status,description,epic"); | ||
| writer.newLine(); | ||
|
|
||
| TreeMap<Integer, Task> 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); | ||
| } | ||
| } | ||
|
|
||
| // Преобразует задачу в строку формата CSV | ||
| private String toString(Task task) { | ||
| StringBuilder builder = new StringBuilder(); | ||
|
|
||
| builder.append(task.getId()).append(","); | ||
| builder.append(task.getType()).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(); | ||
| } | ||
|
|
||
| // Преобразует строку 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; | ||
| } | ||
|
|
||
| // Восстанавливает менеджер из 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); | ||
|
|
||
|
ksupyl marked this conversation as resolved.
|
||
| 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) { | ||
| 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() { | ||
| 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(); | ||
| } | ||
|
|
||
| // Демонстрационный сценарий работы файлового менеджера | ||
| 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("Ошибка: данные после загрузки не совпадают."); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.