Приложение для создания списка дел, написанное на Java

Это первый проект, которым я когда-либо занимался, и теперь, когда я довел его до такой степени, что я чувствую себя комфортно, я хотел бы получить несколько отзывов и советов по его улучшению! Я особенно заинтересован в получении советов по дизайну, удобочитаемости и модульному тестированию части моего кода, и любые советы по улучшению приветствуются!

Я целенаправленно записал все данные в файлы класса Storage, но следующим моим шагом будет реализация базы данных SQL вместе с каким-то графическим интерфейсом, если мне посчастливится получить рецензию на мой проект!

Я еще не написал никаких модульных тестов для класса Storage, и мне интересно, обычно ли это вообще делается? Я полагаю, это потому, что они должны возвращать правильную информацию, но я все равно хотел спросить …

Если в коде есть что-то неясное, спрашивайте, и я уточню!

Вот краткое описание каждой функции классов.

Логин-класс: Отвечает за вход пользователя в систему и возврат правильного пользователя вместе с правильным ToDoList.

RegisterNewUsernameAndPassword-класс: Совершенно очевидно, но он отвечает за создание нового пользователя.

Класс хранения: Отвечает за запись пользователей и списков дел в файл, чтобы их можно было сохранить и загрузить. Также пересылает информацию классу входа в систему и некоторым другим классам.

ToDoList-класс: Отвечает за создание ToDoList для пользователя и связанных методов.

ToDoListTest-класс: Модульные тесты для класса ToDoList.

Пользовательский класс: Определяет параметры для нового пользователя и содержит сеттеры и геттеры.

toDo-класс: Каждый элемент, добавленный в ToDoList, является элементом toDo, и этот класс отвечает за их создание.

UI-класс: Пользовательский интерфейс, который в настоящее время передает информацию пользователю через консоль.

public class UI {

    private final Scanner reader;
    private Storage storage;
    private Login login;
    private RegisterNewUsernameAndPassword registerNew;
    private User user;

    public UI() {
        this.reader = new Scanner(System.in);
        this.storage = new Storage();
        this.login = new Login();
        this.registerNew = new RegisterNewUsernameAndPassword();
    }

    public void start() {
        System.out.println("Login or register");
        String fromUser = reader.nextLine().trim();
        if (fromUser.equalsIgnoreCase("register")) {
            System.out.print("Your username:");
            String userName = reader.nextLine();
            System.out.print("Your first name:");
            String firstName = reader.nextLine();
            System.out.print("Your last name:");
            String lastName = reader.nextLine();
            System.out.print("Your password:");
            String password = reader.nextLine();
            registerNew.createUser(userName, firstName, lastName, password);
        }
        login.logIn();
        this.user = login.returnUser();
        this.user.getUsersToDoList().printToDoList();

        while (true) {
            System.out.println("");
            System.out.println("1: Add a to-do item.");
            System.out.println("2. Remove a to-do item.");
            System.out.println("3. Print a list of my to-do items.");
            System.out.println("4. Quit and save");
            System.out.print("Type the number of desired action: ");

            String input = reader.nextLine();

            if (input.equals("4")) {
                storage.getToDoLists().put(login.returnUsername(), this.user.getUsersToDoList());
                storage.saveUsersToDoLists(storage.getToDoLists());
                System.out.println("Quitting!");
                break;
            } else if (input.equals("1")) {
                System.out.println("What would you like to add?");
                String add = reader.nextLine();
                toDo item = new toDo(add);
                this.user.getUsersToDoList().addToDo(item);
            } else if (input.equals("2")) {
                if (this.user.getUsersToDoList().getList().isEmpty()) {
                    System.out.println("List is empty.");
                    continue;
                }
                System.out.println("");
                this.user.getUsersToDoList().printToDoList();
                System.out.print("Type the index of the item you wish to remove: ");
                int remove = Integer.parseInt(reader.nextLine());
                this.user.getUsersToDoList().removeToDo(remove);
            } else if (input.equals("3")) {
                System.out.println("");
                this.user.getUsersToDoList().printToDoList();
            }
        }
    }
}


public class Login {

    private User user;
    private Storage storage;
    private Scanner reader;
    private String username;

    public Login() {
        this.storage = new Storage();
        this.reader = new Scanner(System.in);
    }

    public void logIn() {
        storage.loadUserNamesAndPasswords(storage.getUsernamesAndPasswordsFile());
        storage.loadUsersToDoLists(storage.getUsersToDoListsFile());
        System.out.println("Username:");
        this.username = reader.nextLine();
        System.out.println("Password:");
        String password = reader.nextLine();
        try {
            if (storage.getUserNamesAndPasswords().get(username).passwordEquals(password) != null) {
                this.user = storage.getUserNamesAndPasswords().get(username);
                this.user.setList(storage.getToDoLists().get(username));
                System.out.println("Welcome " + user.getFirstName() + "!");
            }
        } catch (NullPointerException npe) {
            System.out.println("Incorrect username or password. Please try again!");
            this.logIn();
        }
    }

    public User returnUser() {
        return this.user;
    }

    public String returnUsername() {
        return this.username;
    }
}

public class User implements Serializable {

    private String firstName;
    private String lastName;
    private String password;
    private ToDoList toDoList;

    public User(String firstName, String lastName, String password) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.password = password;
        this.toDoList = new ToDoList();
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public ToDoList getUsersToDoList() {
        return this.toDoList;
    }

    public void setList(ToDoList list) {
        this.toDoList = list;
    }

    public Boolean passwordEquals(String password) {
        return this.password.equals(password);
    }
} 

public class Storage {

    private HashMap<String, ToDoList> toDoLists;
    private HashMap<String, User> map;
    private File UsernamesAndPasswords;
    private File UsersToDoLists;

    Storage() {
        this.UsernamesAndPasswords = new File("UsernamesAndPasswords.ser");
        this.UsersToDoLists = new File("ToDoLists.ser");
        loadUserNamesAndPasswords(UsernamesAndPasswords);
        loadUsersToDoLists(UsersToDoLists);
    }

    public void saveUsersToDoLists(HashMap<String, ToDoList> usersToDoLists) {
        try {
            FileOutputStream fosTwo = new FileOutputStream(UsersToDoLists);
            ObjectOutputStream oosTwo = new ObjectOutputStream(fosTwo);

            oosTwo.writeObject(this.toDoLists);
            oosTwo.flush();
            oosTwo.close();
            fosTwo.close();
        } catch (IOException e) {
            System.out.println("Exception happened. saveUsersList");
        }
    }

    public void loadUsersToDoLists(File file) {
        if (file.length() == 0) {
            toDoLists = new HashMap<>();
            this.saveUsersToDoLists(toDoLists);
        }
        try {
            FileInputStream fisTwo = new FileInputStream(UsersToDoLists);
            ObjectInputStream oisTwo = new ObjectInputStream(fisTwo);

            toDoLists = (HashMap<String, ToDoList>) oisTwo.readObject();
            oisTwo.close();
            fisTwo.close();
        } catch (Exception e) {
            System.out.println("Exception happened. loadUsersList");
        }
    }

    public void saveUserNamesAndPasswords(HashMap<String, User> loginInfo) {
        try {
            FileOutputStream fos = new FileOutputStream(UsernamesAndPasswords);
            ObjectOutputStream oos = new ObjectOutputStream(fos);

            oos.writeObject(this.map);
            oos.flush();
            oos.close();
            fos.close();
        } catch (IOException e) {
            System.out.println("Exception happened. saveUsernames");
        }
    }

    public void loadUserNamesAndPasswords(File file) {
        //If the file is empty then this method creates a new empty hashmap and saves it
        //in the file
        if (file.length() == 0) {
            map = new HashMap<>();
            this.saveUserNamesAndPasswords(map);
        }
        try {
            FileInputStream fis = new FileInputStream(UsernamesAndPasswords);
            ObjectInputStream ois = new ObjectInputStream(fis);

            map = (HashMap<String, User>) ois.readObject();
            ois.close();
            fis.close();
        } catch (Exception e) {
            System.out.println("Exception happened. loadUserNames");
        }
    }

    public HashMap<String, User> getUserNamesAndPasswords () {
        return this.map;
    }

    public File getUsernamesAndPasswordsFile() {
        return this.UsernamesAndPasswords;
        }

    public HashMap<String, ToDoList> getToDoLists() {
        return this.toDoLists;
    }

    public File getUsersToDoListsFile() {
        return this.UsersToDoLists;
    }
}

public class RegisterNewUsernameAndPassword {
    
    private Storage storage;
    private User user;


    public RegisterNewUsernameAndPassword() {
        this.storage = new Storage();
    }

    public void createUser(String userName, String firstName, String lastName, String password) {
        this.user = new User(firstName, lastName, password);
        this.storage.getUserNamesAndPasswords().putIfAbsent(userName, user);
        this.storage.saveUserNamesAndPasswords(storage.getUserNamesAndPasswords());
        this.storage.getToDoLists().putIfAbsent(userName, this.user.getUsersToDoList());
        this.storage.saveUsersToDoLists(storage.getToDoLists());
    }

public class ToDoListTest {
    
    @Test
    public void addToDo(){
        ToDoList todolist = new ToDoList();
        toDo todo = new toDo("Test");
        todolist.addToDo(todo);
        assertTrue(todolist.getList().contains(todo));
    }
    @Test
    public void removeToDo() {
        ToDoList todolist = new ToDoList();
        toDo todo = new toDo("Test");
        todolist.addToDo(todo);
        todolist.removeToDo(1);
        assertFalse(todolist.getList().contains(todo));
    }
    @Test
    public void listIsEmptyWhenCreated() {
        ToDoList todolist = new ToDoList();
        assertTrue(todolist.getList().isEmpty());
    }

    @Test
    public void getList() {
        ToDoList todolist = new ToDoList();
        ArrayList<toDo> list = new ArrayList<>();
        assertEquals(list, todolist.getList());
    }

    @Test
    public void printToDoList() {
        ToDoList todolist = new ToDoList();
        toDo todo = new toDo("Test");
        todolist.addToDo(todo);
        PrintStream oldOut = System.out;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        System.setOut(new PrintStream(baos));
        todolist.printToDoList();
        System.setOut(oldOut);
        String output = baos.toString();
        assertTrue(output.contains("1: Test"));
    }

    @Test
    public void printEmptyToDoList() {
        ToDoList todolist = new ToDoList();
        PrintStream oldOut = System.out;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        System.setOut(new PrintStream(baos));
        todolist.printToDoList();
        System.setOut(oldOut);
        String output = baos.toString();
        assertTrue(output.contains("List is empty."));
    }
}

public class toDo implements Serializable {

    private String name;

    public toDo(String name) {
        this.name = name;
    }

    public void setName(String setName) {
        this.name = setName;
    }

    public String getName() {
        return this.name;
    }

    public String toString() {
        return this.name;
    }
}

public class ToDoList implements Serializable {

    private ArrayList<toDo> toDoList;

    public ToDoList() {
        this.toDoList = new ArrayList<>();
    }

    public void addToDo(toDo toDo) {
        this.toDoList.add(toDo);
    }

    public void removeToDo(int toDo) {
        try {
            this.toDoList.remove(toDo - 1);
        } catch (IndexOutOfBoundsException e) {
            System.out.println("The index you have entered is invalid.");
            System.out.println("Please enter a number between or equal to 1 or " + toDoList.size() + ".");
        }
    }

    public void printToDoList() {
        if (toDoList.isEmpty()) {
            System.out.println("List is empty.");
        } else {
            int i = 1;
            for (toDo todo : toDoList) {
                System.out.println(i + ": " + todo);
                i++;
            }
        }
    }
    public ArrayList<toDo> getList() {
        return this.toDoList;
    }
}

1 ответ
1

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

Вам следует изучить ТВЕРДЫЙ принципы, особенно D (инверсия зависимостей). Ты должен лечить Storage как услуга, предоставляемая друг другу классом. Не то, что классы должны создавать сами. Итак, создайте класс, который загружает один Storage экземпляр и передает этот экземпляр в UI, Login и кому это нужно.

Когда ты думаешь о Storage как услугу, вам необходимо определить операции, которые нужный своими клиентами. Знание местоположения файла имен пользователей и паролей вряд ли имеет отношение к пользовательскому интерфейсу или логину, верно? Таким образом, вы не должны подвергать getUsernamesAndPasswordsFile(). Просто позволь Storage обрабатывать все файлы, связанные с файлами, в частном порядке. Когда вы определили необходимые операции хранения, определить их в интерфейсе и заставить классы использовать интерфейс, а не конкретный класс, который его реализует.

RegisterNewUsernameAndPassword не должно быть класса. Его имя описывает действие, поэтому это должен быть метод в Storage. Вы также должны подумать, имеет ли смысл усложнять ваше приложение учетными записями пользователей, если оно не может использоваться в общей среде. Это проект для начинающих, поэтому вам, возможно, следует сначала сконцентрироваться на создании хорошего однопользовательского приложения, прежде чем подвергать себя множеству сложностей, которые возникают, когда множество пользователей обращаются к одному приложению.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *