diff --git a/README.md b/README.md index 353a9b5..5578fe3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # java-kanban -Repository for homework project. +Sprint 6. +Необходимо: +- Сделать историю посещений неограниченной по размеру. +- Избавиться от повторных просмотров в истории. Если какую-либо задачу посещали несколько раз, то в истории должен остаться только её последний просмотр. Предыдущий должен быть удалён. diff --git a/src/Main.java b/src/Main.java index 55dfbf5..dcd7281 100644 --- a/src/Main.java +++ b/src/Main.java @@ -5,7 +5,6 @@ import service.Managers; import service.TaskManager; - public class Main { public static void main(String[] args) { @@ -15,6 +14,8 @@ public static void main(String[] args) { int task1Id = manager.addNewTask(task1); Task task2 = new Task("Просто Задача - 2", "Описание простой задачи - 2"); int task2Id = manager.addNewTask(task2); + Task task3 = new Task("Просто Задача - 2", "Описание простой задачи - 2"); + int task3Id = manager.addNewTask(task3); Epic epic1 = new Epic("Эпическая задача - 1", "Описание эпической задачи - 1"); @@ -23,31 +24,45 @@ public static void main(String[] args) { "Описание эпической задачи - 2"); int epic2Id = manager.addNewEpic(epic2); - Subtask subtask1 = new Subtask( "Подзадача - 1", + Subtask subtask1 = new Subtask("Подзадача - 1", "Описание подзадачи - 1, эпической задачи - 1", epic1.getId()); int subtask1Id = manager.addNewSubtask(subtask1); Subtask subtask2 = new Subtask("Подзадача - 2", -"Описание подзадачи - 2, эпической задачи - 1", epic1.getId()); + "Описание подзадачи - 2, эпической задачи - 1", epic1.getId()); int subtask2Id = manager.addNewSubtask(subtask2); - Subtask subtask3 = new Subtask( "Подзадача - 3", - "Описание подзадачи - 3, эпической задачи - 2", epic2.getId()); + Subtask subtask3 = new Subtask("Подзадача - 3", + "Описание подзадачи - 3, эпической задачи - 1", epic1.getId()); int subtask3Id = manager.addNewSubtask(subtask3); - manager.getTask(2); - manager.getTask(1); - manager.getTask(2); - manager.getEpic(4); - manager.getSubtask(6); - manager.getSubtask(5); - manager.getEpic(3); - manager.getSubtask(7); - manager.getTask(1); - manager.getTask(1); - manager.getSubtask(6); - manager.getSubtask(5); + manager.getTask(task2Id); + manager.getTask(task1Id); + manager.getTask(task2Id); + manager.getEpic(epic2Id); + manager.getSubtask(subtask2Id); + manager.getSubtask(subtask1Id); + manager.getEpic(epic1Id); + manager.getSubtask(subtask3Id); + manager.getTask(task3Id); + manager.getTask(task1Id); + manager.getSubtask(subtask2Id); + manager.getSubtask(subtask1Id); printAllTasks(manager); + printHistory(manager); + + manager.deleteTask(task1Id); + System.out.println("\n Удаляем задачу - 1"); + printHistory(manager); + + manager.deleteEpic(epic1Id); + System.out.println("\n Удаляем эпик - 1 с тремя подзадачами"); + printHistory(manager); + + manager.deleteAllTasks(); + System.out.println("\n Удаляем все задачи"); + printHistory(manager); } + private static void printAllTasks(TaskManager manager) { System.out.println("Задачи:"); for (Task task : manager.getAllTasks()) { @@ -65,8 +80,10 @@ private static void printAllTasks(TaskManager manager) { for (Task subtask : manager.getAllSubtasks()) { System.out.println(subtask); } + } - System.out.println("История:"); + private static void printHistory(TaskManager manager) { + System.out.println("\nИстория:"); for (Task task : manager.getHistory()) { System.out.println(task); } diff --git a/src/model/Epic.java b/src/model/Epic.java index e9d193a..62d6059 100644 --- a/src/model/Epic.java +++ b/src/model/Epic.java @@ -1,10 +1,11 @@ package model; import java.util.ArrayList; +import java.util.List; public class Epic extends Task { - private final ArrayList subtaskIds = new ArrayList<>(); + private final List subtaskIds = new ArrayList<>(); public Epic(int id, String title, String description, Status status) { super(id, title, description, status); @@ -19,7 +20,7 @@ public void addSubtaskId(int subtaskId) { this.subtaskIds.add(subtaskId); } - public ArrayList getSubtaskIds() { + public List getSubtaskIds() { return subtaskIds; } diff --git a/src/service/HistoryManager.java b/src/service/HistoryManager.java index 8e98267..136e3bd 100644 --- a/src/service/HistoryManager.java +++ b/src/service/HistoryManager.java @@ -6,5 +6,8 @@ public interface HistoryManager { void addInHistory(Task task); + + void removeFromHistory(int id); + List getHistory(); } diff --git a/src/service/InMemoryHistoryManager.java b/src/service/InMemoryHistoryManager.java index 3fdf116..de3b402 100644 --- a/src/service/InMemoryHistoryManager.java +++ b/src/service/InMemoryHistoryManager.java @@ -3,28 +3,74 @@ import model.Task; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class InMemoryHistoryManager implements HistoryManager { - private static final int SIZE_HISTORY = 10; - private final List history = new ArrayList<>(SIZE_HISTORY); - - private void removeHistoryFirst() { - if (!history.isEmpty() && history.size() == SIZE_HISTORY) { - history.removeFirst(); - } - } + private Node head = null; + private Node tail = null; + private final Map listHistory = new HashMap<>(); @Override public List getHistory() { - return new ArrayList<>(history); + return getTasks(); } @Override public void addInHistory(Task task) { if (task != null) { - removeHistoryFirst(); - history.add(task); + removeFromHistory(task.getId()); + linkLast(task); + } + } + + private void linkLast(Task task) { + Node newNode = new Node(task, null, tail); + if (tail == null) { + head = newNode; + } else { + tail.setNext(newNode); + } + tail = newNode; + listHistory.put(task.getId(), newNode); + } + + @Override + public void removeFromHistory(int id) { + if (listHistory.containsKey(id)) { + removeNode(listHistory.get(id)); + } + } + + private List getTasks() { + List listHistoryRes = new ArrayList<>(); + Node node = head; + while (node != null) { + listHistoryRes.add(node.getItem()); + node = node.getNext(); + } + return listHistoryRes; + } + + private void removeNode(Node node) { + if (node != null) { + Node nodeNext = node.getNext(); + Node nodePrev = node.getPrev(); + if (head == node) { + head = nodeNext; + } + if (tail == node) { + tail = nodePrev; + } + + if (nodePrev != null) { + nodePrev.setNext(nodeNext); + } + + if (nodeNext != null) { + nodeNext.setPrev(nodePrev); + } } } } diff --git a/src/service/InMemoryTaskManager.java b/src/service/InMemoryTaskManager.java index 82523a3..7e2cfc9 100644 --- a/src/service/InMemoryTaskManager.java +++ b/src/service/InMemoryTaskManager.java @@ -8,11 +8,12 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; public class InMemoryTaskManager implements TaskManager { - private final HashMap tasks = new HashMap<>(); - private final HashMap epics = new HashMap<>(); - private final HashMap subtasks = new HashMap<>(); + private final Map tasks = new HashMap<>(); + private final Map epics = new HashMap<>(); + private final Map subtasks = new HashMap<>(); private int id = 0; private final HistoryManager inMemoryHistoryManager = Managers.getDefaultHistory(); @@ -34,11 +35,13 @@ public List getAllEpics() { @Override public void deleteAllTasks() { + deleteAllTasksFromHistory(tasks); tasks.clear(); } @Override public void deleteAllSubtasks() { + deleteAllTasksFromHistory(subtasks); for (Epic epic : epics.values()) { epic.getSubtaskIds().clear(); updateStatusEpic(epic.getId()); @@ -48,7 +51,9 @@ public void deleteAllSubtasks() { @Override public void deleteAllEpics() { + deleteAllTasksFromHistory(subtasks); subtasks.clear(); + deleteAllTasksFromHistory(epics); epics.clear(); } @@ -137,6 +142,7 @@ public void updateEpic(Epic epic) { @Override public void deleteTask(int id) { + inMemoryHistoryManager.removeFromHistory(id); tasks.remove(id); } @@ -145,8 +151,8 @@ public void deleteSubtask(Integer id) { if (subtasks.containsKey(id)) { int epicId = subtasks.get(id).getEpicId(); Epic epic = epics.get(epicId); - epic.getSubtaskIds().remove(id); + inMemoryHistoryManager.removeFromHistory(id); subtasks.remove(id); updateStatusEpic(epicId); } @@ -156,12 +162,14 @@ public void deleteSubtask(Integer id) { public void deleteEpic(int epicId) { if (epics.containsKey(epicId)) { Epic epic = epics.get(epicId); - ArrayList subtaskIdsClone = new ArrayList<>(epic.getSubtaskIds()); + List subtaskIdsClone = new ArrayList<>(epic.getSubtaskIds()); for (Integer subtaskId : subtaskIdsClone) { + inMemoryHistoryManager.removeFromHistory(subtaskId); epic.getSubtaskIds().remove(subtaskId); subtasks.remove(subtaskId); } + inMemoryHistoryManager.removeFromHistory(epicId); epics.remove(epicId); } } @@ -210,4 +218,10 @@ public void updateStatusEpic(int epicId) { } } } + + private void deleteAllTasksFromHistory(Map tasksToDelete) { + for (Integer keyId : tasksToDelete.keySet()) { + inMemoryHistoryManager.removeFromHistory(keyId); + } + } } diff --git a/src/service/Node.java b/src/service/Node.java new file mode 100644 index 0000000..8cf7ef1 --- /dev/null +++ b/src/service/Node.java @@ -0,0 +1,39 @@ +package service; + +import model.Task; + +public class Node { + private Task item; + private Node next; + private Node prev; + + public Node(Task item, Node next, Node prev) { + this.item = item; + this.next = next; + this.prev = prev; + } + + public Task getItem() { + return item; + } + + public void setItem(Task item) { + this.item = item; + } + + public Node getNext() { + return next; + } + + public void setNext(Node next) { + this.next = next; + } + + public Node getPrev() { + return prev; + } + + public void setPrev(Node prev) { + this.prev = prev; + } +} diff --git a/test/service/InMemoryHistoryManagerTest.java b/test/service/InMemoryHistoryManagerTest.java index 9851d18..fe686e1 100644 --- a/test/service/InMemoryHistoryManagerTest.java +++ b/test/service/InMemoryHistoryManagerTest.java @@ -5,6 +5,7 @@ import model.Task; import java.util.List; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; @@ -13,54 +14,125 @@ public class InMemoryHistoryManagerTest { private TaskManager manager; private Task task; + private Task task2; private Epic epic; + private Epic epic2; @BeforeEach void setUp() { task = new Task("Просто задача - 1", "Описание простой задачи - 1"); + task2 = new Task("Просто задача - 2", "Описание простой задачи - 2"); epic = new Epic("Эпическая задача - 1", "Описание эпической задачи - 1"); + epic2 = new Epic("Эпическая задача - 2", + "Описание эпической задачи - 2"); manager = Managers.getDefault(); } @Test void addTaskInHistoryTest() { - final int taskId = manager.addNewTask(task); + final int taskId1 = manager.addNewTask(task); + final int taskId2 = manager.addNewTask(task2); + manager.getTask(taskId1); + manager.getTask(taskId2); + + final List history = manager.getHistory(); - manager.getTask(taskId); + assertNotNull(history, "История не пустая."); + assertEquals(2, history.size(), "Размер истории не верный"); + assertEquals(List.of(task, task2), manager.getHistory(), "История не соответствует"); + } + + @Test + void removeTaskFromHistoryTest() { + final int taskId1 = manager.addNewTask(task); + final int taskId2 = manager.addNewTask(task2); + manager.getTask(taskId1); + manager.getTask(taskId2); + manager.getTask(taskId1); final List history = manager.getHistory(); assertNotNull(history, "История не пустая."); - assertEquals(1, history.size(), "История не пустая."); + assertEquals(2, history.size(), "Размер истории не верный"); + assertEquals(List.of(task2, task), manager.getHistory(), "История не соответствует"); } @Test void addEpicInHistoryTest() { - final int epicId = manager.addNewEpic(epic); + final int epicId1 = manager.addNewEpic(epic); + final int epicId2 = manager.addNewEpic(epic2); + manager.getEpic(epicId1); + manager.getEpic(epicId2); - manager.getEpic(epicId); + final List history = manager.getHistory(); + + assertNotNull(history, "История не пустая."); + assertEquals(2, history.size(), "Размер истории не верный"); + assertEquals(List.of(epic, epic2), manager.getHistory(), "История не соответствует"); + } + + @Test + void removeEpicInHistoryTest() { + final int epicId1 = manager.addNewEpic(epic); + final int epicId2 = manager.addNewEpic(epic2); + manager.getEpic(epicId1); + manager.getEpic(epicId2); + manager.getEpic(epicId1); final List history = manager.getHistory(); assertNotNull(history, "История не пустая."); - assertEquals(1, history.size(), "История не пустая."); + assertEquals(2, history.size(), "Размер истории не верный"); + assertEquals(List.of(epic2, epic), manager.getHistory(), "История не соответствует"); } @Test void addSubtaskInHistoryTest() { - final int epicId = manager.addNewEpic(epic); - Subtask subtask = new Subtask("Подзадача - 1", - "Описание подзадачи - 1, эпической задачи - 1", epicId); - final int subtaskId = manager.addNewSubtask(subtask); + final int epicId1 = manager.addNewEpic(epic); + final int epicId2 = manager.addNewEpic(epic2); + Subtask subtask1 = new Subtask("Подзадача - 1", + "Описание подзадачи - 1, эпической задачи - 1", epicId1); + Subtask subtask2 = new Subtask("Подзадача - 1", + "Описание подзадачи - 1, эпической задачи - 2", epicId2); + final int subtaskId1 = manager.addNewSubtask(subtask1); + final int subtaskId2 = manager.addNewSubtask(subtask2); + + manager.getEpic(epicId1); + manager.getSubtask(subtaskId1); + manager.getEpic(epicId2); + manager.getSubtask(subtaskId2); - manager.getEpic(epicId); - manager.getSubtask(subtaskId); + final List history = manager.getHistory(); + + assertNotNull(history, "История не пустая."); + assertEquals(4, history.size(), "Размер истории не верный"); + assertEquals(List.of(epic, subtask1, epic2, subtask2), manager.getHistory(), "История не соответствует"); + } + + @Test + void removeSubtaskInHistoryTest() { + final int epicId1 = manager.addNewEpic(epic); + final int epicId2 = manager.addNewEpic(epic2); + Subtask subtask1 = new Subtask("Подзадача - 1", + "Описание подзадачи - 1, эпической задачи - 1", epicId1); + Subtask subtask2 = new Subtask("Подзадача - 1", + "Описание подзадачи - 1, эпической задачи - 2", epicId2); + final int subtaskId1 = manager.addNewSubtask(subtask1); + final int subtaskId2 = manager.addNewSubtask(subtask2); + + manager.getEpic(epicId1); + manager.getSubtask(subtaskId1); + manager.getEpic(epicId2); + manager.getSubtask(subtaskId2); + manager.getSubtask(subtaskId1); + manager.getEpic(epicId2); final List history = manager.getHistory(); assertNotNull(history, "История не пустая."); - assertEquals(2, history.size(), "История не пустая."); + assertEquals(4, history.size(), "Размер истории не верный"); + assertEquals(List.of(epic, subtask2, subtask1, epic2), manager.getHistory(), "История не соответствует"); } @Test @@ -72,10 +144,25 @@ void getHistoryTest() { manager.getEpic(epicId); manager.getSubtask(subtaskId); + manager.getEpic(epicId); final List history = manager.getHistory(); - assertEquals(history.get(0), epic, "История возвращается неверно"); - assertEquals(history.get(1), subtask, "История возвращается неверно"); + assertEquals(history.get(0), subtask, "История возвращается неверно"); + assertEquals(history.get(1), epic, "История возвращается неверно"); + } + + @Test + void deleteAllTasksFromHistoryTest() { + int taskId1 = manager.addNewTask(task); + int taskId2 = manager.addNewTask(task2); + manager.getTask(taskId1); + manager.getTask(taskId2); + + manager.deleteAllTasks(); + + List history = manager.getHistory(); + + assertTrue(history.isEmpty(), "Задачи не удалились"); } } diff --git a/test/service/TaskManagerTest.java b/test/service/TaskManagerTest.java index 2fa8ca1..b9ba58a 100644 --- a/test/service/TaskManagerTest.java +++ b/test/service/TaskManagerTest.java @@ -168,13 +168,18 @@ void deleteAllEpicsTest() { @Test void deleteSubtaskTest() { + manager.addNewEpic(epic); Subtask subtask = new Subtask("Подзадача - 1", "Описание подзадачи - 1, эпической задачи - 1", epic.getId()); - int subtaskId = manager.addNewSubtask(subtask); + Integer subtaskId = manager.addNewSubtask(subtask); + + assertEquals(1, epic.getSubtaskIds().size(), "ID сабтаски не зарегистрировался у эпика"); + manager.deleteSubtask(subtaskId); assertTrue(manager.getAllSubtasks().isEmpty(), "Сабтаск не удалился"); assertEquals(0, manager.getAllSubtasks().size(), "Сабтаск не удалился"); + assertTrue(epic.getSubtaskIds().isEmpty(), "ID сабтаски не удалился из списка у эпика"); } @Test