Skip to content

Создать вторую реализацию менеджера - FileBackedTaskManager - #3

Merged
AleksOBM merged 8 commits into
mainfrom
sprint_7-solution-in-file-manager
Oct 23, 2025
Merged

Создать вторую реализацию менеджера - FileBackedTaskManager#3
AleksOBM merged 8 commits into
mainfrom
sprint_7-solution-in-file-manager

Conversation

@AleksOBM

Copy link
Copy Markdown
Owner

Подготовить проект к первому ревью седьмого спринта

Comment thread src/manager/FileBackedTaskManager.java Outdated
import java.nio.charset.StandardCharsets;
import java.util.*;

public class FileBackedTaskManager extends InMemoryTaskManager implements TaskManager {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

достаточно объявить extends InMemoryTaskManager, чтобы неявно уже было, что класс FileBackedTasksManager реализует интерфейс TaskManager

Comment thread src/manager/FileBackedTaskManager.java Outdated
}
try {
reader = new FileReader(this.file, charset);
bufferedReader = new BufferedReader(reader);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

можно сделать вот так new BufferedReader(new FileReader(file.getPath(), charset)) и не создавать не нужную переменную

Comment thread src/manager/FileBackedTaskManager.java Outdated
}

if (counter < taskObject.getId()) {
counter++;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не нужно наугад поднимать значение счетчика. Например: в файле две сущности с id равными 2 и 4, потому что сущности с id равными 1 и 3 удалили. Соответсветственно после вычитки из файла counter станет 3 и следующая же создаваемая сущность перетрет существующую (если они будут одного типа) или появятся две сущности с одним id (если они будут разного типа). Поэтому нужно найти наибольшее значение id из файла, потом сделать +1 и после этого передать его в counter.

Comment thread src/manager/FileBackedTaskManager.java Outdated
}

if (taskObject instanceof Epic) {
super.setEpic((Epic) taskObject);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

здесь нельзя пользоваться методом setEpic(), потому что в нем сущности будет присвоено новое id. Нужно в InMemoryTaskManager заготовить protected метод, который будет наполнять соответсвующее хранилище полученными сущностями

Comment thread src/manager/FileBackedTaskManager.java Outdated

} catch (IOException e) {
try {
throw new ManagerSaveException("Файл не прочитан");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

перехватывать ManagerSaveException не нужно

Comment thread src/manager/FileBackedTaskManager.java Outdated
}
}

save();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не нужно при вычитке из файла еще и сохранять в него

Comment thread src/manager/FileBackedTaskManager.java Outdated
}

} catch (IOException e) {
System.out.println(e.getMessage());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

тут нужно бросить ManagerSaveException с комментарием

return null;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

переопределяй только те методы, которые отличаются от родительских. в родительском исполнении они итак доступны в дочерних классах

Comment thread src/exception/ManagerSaveException.java Outdated
@@ -0,0 +1,7 @@
package exception;

public class ManagerSaveException extends Exception {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

сделай наследование от RuntimeException

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Готово

Comment thread src/manager/FileBackedTaskManager.java Outdated
return;
}

counter = taskObject.getId();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

нет контракта, что в файле сущности пишутся в порядке возрастания id, поэтому сначала нужно найти самое большое значение в файле, только потом, после цикла его передать в counter

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод getAll() возвращает их отсортированными.
В Task добавлен метод compareTo().

 public List<Task> getAll() {
        if (counter == 1) {
            return new ArrayList<>();
        }
        TreeSet<Task> allTasks = new TreeSet<>();

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Готово

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вижу ты переделал, но все же поясню, чтобы было понятнее. Чтобы переопределить порядок хранения в TreeSet нужно при создании в сам TreeSet передать объект Comparator в котором будет указан порядок сортировки. Переопределение метода compareTo() в объектах хранения не распространяется на само хранилище

Comment thread src/manager/FileBackedTaskManager.java Outdated
counter = taskObject.getId();

if (taskObject instanceof Epic) {
super.setEpic((Epic) taskObject);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не используй методы создания сущностей. Здесь не новая сущность, а старая, которую пользователь создал вчера, позавчера и т.д. Добавь в InMemoryTaskManager метод или отдельные методы, которые будут просто наполнять хранилища данными

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Боюсь в таком случае будет вероятность коллизий по айди.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Или counter лучше вообще не трогать?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тогда может расшарить хранилище?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

готово

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так же поясню для лучшего понимания. Тут было два варианта (но по сути это одно и тоже).

  1. Сами хранилища и counter сделать protected, т.е. доступными в классах наследниках. Соответственно наследник может изменять состояние этих объектов, т.е. наполнить хранилища и указать counter указать следующее значение, чтобы новая сущность получила свое уникальное id
  2. Все тоже самое мог ди делать пару методов в классе InMemoryTaskManager, получая на вход от наследников (т.е. тоже был бы protected) вычитанные сущности и новое (т.е. max + 1) значение для counter

}
}

@Override

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

общий комментарий к переопределенным метода: не нужно перехватывать ManagerSaveException, когда он будет отнаследован от RuntimeException, он будет без проблем выбрасываться

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Готово

Comment thread src/manager/FileBackedTaskManager.java Outdated
public Task setTask(Task newTask) {
Task result = null;
try {
checkAndReloadFileData();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

нет смысла перепроверять файл, в методе save() он будет перезаписан начисто из данных хранилищ (idToTask, idToEpic, idToSubtask) начисто

@AleksOBM AleksOBM Oct 22, 2025

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я подумал, а что если в процессе работы программы кто-то изменит файл?
Написал тест на эту тему.

@Test
    void shouldReturnValidSubtaskAfterReloadFileWhereOneElementHasRemoved() {
        manager.removeTask(1);

        manager2 = new FileBackedTaskManager(file);
        manager2.removeSubtask(4);
        manager2.setEpic((Epic) manager.get(2).getCopy());

        manager.setTask(new Task(1,"1","1",null));

        FileBackedTaskManager manager3 = new FileBackedTaskManager(file);
        String title = manager3.getTask(6).getTitle();
        assertEquals("1", title,
                "Менеджер не отслеживает изменения произведенные в файле извне.");
    }

Сейчас прежде чем что-то сделать с файлом, менеджер проверяет, не изменились ли данные в файле.
Если например была удалена последняя задача, он не присвоит новой задаче тот-же айди что и у удаленной.
А ты предлагаешь смотреть какой айди в файле был последним, мне кажется это не правильно с точки зрения назначения идентификаторов. Удаленный айди больше не должен создаваться.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Готово

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ты решил усложнить себе задачу))) такого на учебном проекте не требуется))

import java.util.Map;
import java.util.*;

class InMemoryTaskManager implements TaskManager {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

в этом классе не должно быть использование ManagerSaveException.
Вся доработка текущего класса - это доступность некоторых его полей для классов-наследников (через изменение их модификатора доступа с private на protected или же через добавление protected методов, которые будут работать с этими полями - тут на твой выбор)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я это понял уже после того как дописал методы:
Task get(int id)
Task getWithoutHistory(int id)
Type getType(int id)
List getAll()

Хотя, думаю они давно уже напрашивались.

ManagerSaveException - убрал.

@AleksOBM
AleksOBM merged commit 3b4af51 into main Oct 23, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants