refactor: restructure application using MVP architecture

This commit is contained in:
2026-08-26 19:01:39 +04:00
parent 3a77ce7d88
commit 1ee2fc3d06
18 changed files with 266 additions and 292 deletions
+24 -17
View File
@@ -2,39 +2,46 @@ package ru.project;
import com.googlecode.lanterna.gui2.MultiWindowTextGUI;
import com.googlecode.lanterna.screen.Screen;
import com.googlecode.lanterna.screen.TerminalScreen;
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
import ru.project.ui.MainMenu;
import ru.project.ui.Navigator;
import ru.project.model.AppState;
import ru.project.presenter.MainPresenter;
import ru.project.view.MainView;
public final class App {
private App() {}
public static void main(String[] args) throws Exception {
DefaultTerminalFactory factory = new DefaultTerminalFactory();
Screen screen = new TerminalScreen(factory.createTerminal());
screen.startScreen();
public static void main(String[] args) {
Screen screen = null;
try {
DefaultTerminalFactory terminalFactory = new DefaultTerminalFactory();
screen = terminalFactory.createScreen();
screen.startScreen();
MultiWindowTextGUI gui = new MultiWindowTextGUI(screen);
// Application state
AppState state = new AppState();
MainView view = new MainView();
// Controllers
CollectionController collectionController = new CollectionController(state);
MainPresenter presenter = new MainPresenter(state, view, gui);
// Navigation
Navigator navigator = new Navigator(gui, collectionController);
presenter.start();
// Application entry point
gui.addWindowAndWait(new MainMenu(navigator));
} catch (Exception e) {
System.err.println("Произошла ошибка при выполнении программы:");
e.printStackTrace();
} finally {
screen.stopScreen();
if (screen != null) {
try {
screen.stopScreen();
} catch (Exception e) {
System.err.println("Не удалось корректно завершить работу терминала:");
e.printStackTrace();
}
}
}
}
}
@@ -1,18 +0,0 @@
package ru.project;
public class AppState {
private DataCollection collection;
public DataCollection getCollection() {
return collection;
}
public void setCollection(DataCollection collection) {
this.collection = collection;
}
public boolean hasCollection() {
return collection != null;
}
}
@@ -1,49 +0,0 @@
package ru.project;
public class CollectionController {
private final AppState state;
public CollectionController(AppState state) {
this.state = state;
}
public void createCollection() {
DataCollection collection = new DataCollection();
collection.add("Charlie");
collection.add("Alice");
collection.add("Bob");
collection.add("Alice");
state.setCollection(collection);
}
public DataCollection getCollection() {
return state.getCollection();
}
public boolean hasCollection() {
return state.hasCollection();
}
public void sortCollection() {
if (!state.hasCollection()) {
return;
}
state.getCollection().sort();
}
public boolean contains(String element) {
return state.hasCollection() && state.getCollection().contains(element);
}
public int countOccurrences(String element) {
if (!state.hasCollection()) {
return 0;
}
return state.getCollection().count(element);
}
}
@@ -1,47 +0,0 @@
package ru.project;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class DataCollection {
private final List<String> elements = new ArrayList<>();
public void add(String element) {
elements.add(element);
}
public void sort() {
Collections.sort(elements);
}
public boolean contains(String element) {
return elements.contains(element);
}
public int count(String element) {
int count = 0;
for (String current : elements) {
if (current.equals(element)) {
count++;
}
}
return count;
}
public List<String> getElements() {
return Collections.unmodifiableList(elements);
}
@Override
public String toString() {
if (elements.isEmpty()) {
return "Коллекция пуста";
}
return String.join(", ", elements);
}
}
@@ -0,0 +1,32 @@
package ru.project.model;
import ru.project.collection.MyLinkedList;
import ru.project.collection.MyList;
import ru.project.student.Student;
public class AppState {
private MyList<Student> collection;
private String currentFilePath;
public AppState() {
this.collection = new MyLinkedList<>();
this.currentFilePath = null;
}
public MyList<Student> getCollection() {
return collection;
}
public void setCollection(MyList<Student> collection) {
this.collection = collection;
}
public String getCurrentFilePath() {
return currentFilePath;
}
public void setCurrentFilePath(String currentFilePath) {
this.currentFilePath = currentFilePath;
}
}
@@ -0,0 +1,31 @@
package ru.project.presenter;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import ru.project.collection.MyList;
import ru.project.model.AppState;
import ru.project.student.Student;
import ru.project.view.CollectionView;
public class CollectionPresenter {
private final AppState state;
private final CollectionView view;
private final WindowBasedTextGUI gui;
public CollectionPresenter(AppState state, CollectionView view, WindowBasedTextGUI gui) {
this.state = state;
this.view = view;
this.gui = gui;
}
public void start() {
MyList<Student> collection = state.getCollection();
if (collection == null || collection.isEmpty()) {
view.showEmptyMessage(gui);
return;
}
view.showCollection(gui, collection);
}
}
@@ -0,0 +1,70 @@
package ru.project.presenter;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import com.googlecode.lanterna.gui2.dialogs.MessageDialog;
import com.googlecode.lanterna.gui2.dialogs.MessageDialogButton;
import ru.project.model.AppState;
import ru.project.view.CollectionView;
import ru.project.view.MainView;
public class MainPresenter {
private final AppState state;
private final MainView view;
private final WindowBasedTextGUI gui;
private final CollectionPresenter collectionPresenter;
public MainPresenter(AppState state, MainView view, WindowBasedTextGUI gui) {
this.state = state;
this.view = view;
this.gui = gui;
this.collectionPresenter = new CollectionPresenter(state, new CollectionView(), gui);
}
public void start() {
bindActions();
view.show(gui);
}
private void bindActions() {
view.setShowCollectionAction(this::showCollection);
view.setCreateCollectionAction(this::createCollection);
view.setSaveCollectionAction(this::saveCollection);
view.setSortCollectionAction(this::sortCollection);
view.setSearchCollectionAction(this::searchCollection);
view.setCountOccurrencesAction(this::countOccurrences);
view.setExitAction(this::exit);
}
private void showCollection() {
collectionPresenter.start();
}
private void createCollection() {
showMessage("Меню создания коллекции.");
}
private void saveCollection() {
showMessage("Меню сохранения коллекции.");
}
private void sortCollection() {
showMessage("Меню сортировки коллекции.");
}
private void searchCollection() {
showMessage("Меню поиска элемента.");
}
private void countOccurrences() {
showMessage("Меню подсчёта количества вхождений.");
}
private void exit() {
view.close();
}
private void showMessage(String message) {
MessageDialog.showMessageDialog(gui, "Информация", message, MessageDialogButton.OK);
}
}
@@ -1,10 +0,0 @@
package ru.project.ui;
import ru.project.CollectionController;
public class CollectionView extends EmptyMenu {
public CollectionView(CollectionController controller) {
super("Текущая коллекция");
}
}
@@ -1,10 +0,0 @@
package ru.project.ui;
import ru.project.CollectionController;
public class CountOccurrencesMenu extends EmptyMenu {
public CountOccurrencesMenu(CollectionController controller) {
super("Подсчёт количества вхождений");
}
}
@@ -1,10 +0,0 @@
package ru.project.ui;
import ru.project.CollectionController;
public class CreateCollectionMenu extends EmptyMenu {
public CreateCollectionMenu(CollectionController controller) {
super("Создание новой коллекции");
}
}
@@ -1,23 +0,0 @@
package ru.project.ui;
import com.googlecode.lanterna.gui2.BasicWindow;
import com.googlecode.lanterna.gui2.Button;
import com.googlecode.lanterna.gui2.Direction;
import com.googlecode.lanterna.gui2.Label;
import com.googlecode.lanterna.gui2.LinearLayout;
import com.googlecode.lanterna.gui2.Panel;
public abstract class EmptyMenu extends BasicWindow {
protected EmptyMenu(String title) {
super(title);
Panel panel = new Panel(new LinearLayout(Direction.VERTICAL));
panel.addComponent(new Label("Раздел находится в разработке"));
panel.addComponent(new Button("Назад", this::close));
setComponent(panel);
}
}
@@ -1,34 +0,0 @@
package ru.project.ui;
import com.googlecode.lanterna.gui2.BasicWindow;
import com.googlecode.lanterna.gui2.Button;
import com.googlecode.lanterna.gui2.Direction;
import com.googlecode.lanterna.gui2.LinearLayout;
import com.googlecode.lanterna.gui2.Panel;
public class MainMenu extends BasicWindow {
public MainMenu(Navigator navigator) {
super("ГЛАВНОЕ МЕНЮ");
Panel panel = new Panel(new LinearLayout(Direction.VERTICAL));
panel.addComponent(new Button("Показать текущую коллекцию", navigator::showCollectionView));
panel.addComponent(new Button("Создать новую коллекцию", navigator::showCreateCollection));
panel.addComponent(
new Button("Сохранить текущую коллекцию в файл", navigator::showSaveCollection));
panel.addComponent(new Button("Сортировать текущую коллекцию", navigator::showSortCollection));
panel.addComponent(new Button("Найти элемент", navigator::showSearchElement));
panel.addComponent(
new Button("Подсчитать количество вхождений", navigator::showCountOccurrences));
panel.addComponent(new Button("Завершить выполнение программы", this::close));
setComponent(panel);
}
}
@@ -1,44 +0,0 @@
package ru.project.ui;
import com.googlecode.lanterna.gui2.BasicWindow;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import ru.project.CollectionController;
public class Navigator {
private final WindowBasedTextGUI gui;
private final CollectionController collectionController;
public Navigator(WindowBasedTextGUI gui, CollectionController collectionController) {
this.gui = gui;
this.collectionController = collectionController;
}
public void show(BasicWindow window) {
gui.addWindowAndWait(window);
}
public void showCollectionView() {
show(new CollectionView(collectionController));
}
public void showCreateCollection() {
show(new CreateCollectionMenu(collectionController));
}
public void showSaveCollection() {
show(new SaveCollectionMenu(collectionController));
}
public void showSortCollection() {
show(new SortCollectionMenu(collectionController));
}
public void showSearchElement() {
show(new SearchElementMenu(collectionController));
}
public void showCountOccurrences() {
show(new CountOccurrencesMenu(collectionController));
}
}
@@ -1,10 +0,0 @@
package ru.project.ui;
import ru.project.CollectionController;
public class SaveCollectionMenu extends EmptyMenu {
public SaveCollectionMenu(CollectionController controller) {
super("Сохранение текущей коллекции");
}
}
@@ -1,10 +0,0 @@
package ru.project.ui;
import ru.project.CollectionController;
public class SearchElementMenu extends EmptyMenu {
public SearchElementMenu(CollectionController controller) {
super("Поиск элемента");
}
}
@@ -1,10 +0,0 @@
package ru.project.ui;
import ru.project.CollectionController;
public class SortCollectionMenu extends EmptyMenu {
public SortCollectionMenu(CollectionController controller) {
super("Сортировка текущей коллекции");
}
}
@@ -0,0 +1,47 @@
package ru.project.view;
import com.googlecode.lanterna.gui2.BasicWindow;
import com.googlecode.lanterna.gui2.Button;
import com.googlecode.lanterna.gui2.Label;
import com.googlecode.lanterna.gui2.LinearLayout;
import com.googlecode.lanterna.gui2.Panel;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import ru.project.collection.MyList;
import ru.project.student.Student;
public class CollectionView {
public void showCollection(WindowBasedTextGUI gui, MyList<Student> collection) {
BasicWindow window = new BasicWindow("Текущая коллекция");
Panel panel = new Panel();
panel.setLayoutManager(new LinearLayout());
for (int i = 0; i < collection.size(); i++) {
Student student = collection.get(i);
panel.addComponent(new Label((i + 1) + ". " + student));
}
panel.addComponent(new Button("Вернуться", window::close));
window.setComponent(panel);
gui.addWindowAndWait(window);
}
public void showEmptyMessage(WindowBasedTextGUI gui) {
BasicWindow window = new BasicWindow("Текущая коллекция");
Panel panel = new Panel();
panel.setLayoutManager(new LinearLayout());
panel.addComponent(new Label("Текущая коллекция пуста."));
panel.addComponent(new Button("Вернуться", window::close));
window.setComponent(panel);
gui.addWindowAndWait(window);
}
}
@@ -0,0 +1,62 @@
package ru.project.view;
import com.googlecode.lanterna.gui2.ActionListBox;
import com.googlecode.lanterna.gui2.BasicWindow;
import com.googlecode.lanterna.gui2.LinearLayout;
import com.googlecode.lanterna.gui2.Panel;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
public class MainView {
private final BasicWindow window;
private final ActionListBox menu;
public MainView() {
window = new BasicWindow("Главное меню");
Panel panel = new Panel();
panel.setLayoutManager(new LinearLayout());
menu = new ActionListBox();
panel.addComponent(menu);
window.setComponent(panel);
}
public void setShowCollectionAction(Runnable action) {
menu.addItem("Показать текущую коллекцию", action);
}
public void setCreateCollectionAction(Runnable action) {
menu.addItem("Меню создания новой коллекции", action);
}
public void setSaveCollectionAction(Runnable action) {
menu.addItem("Меню сохранения текущей коллекции в файл", action);
}
public void setSortCollectionAction(Runnable action) {
menu.addItem("Меню сортировки текущей коллекции", action);
}
public void setSearchCollectionAction(Runnable action) {
menu.addItem("Меню поиска элемента в текущей коллекции", action);
}
public void setCountOccurrencesAction(Runnable action) {
menu.addItem("Меню подсчёта количества вхождений элемента", action);
}
public void setExitAction(Runnable action) {
menu.addItem("Завершить выполнение программы", action);
}
public void show(WindowBasedTextGUI gui) {
gui.addWindowAndWait(window);
}
public void close() {
window.close();
}
}