проект: Simple File Manager. структура кода, лучшие практики

Рейтинг: -1Ответов: 0Опубликовано: 07.08.2025

задание выполнено и код рабочий. Java17, юнит тесты по заданию не требуются. прошу дать обратную связь:

  1. по архитектуре и делению на классы/интерфейсы
  2. по улучшению стиля написания кода
  3. посоветовать лучшие практики: где, как и почему нужно писать по-другому
  4. любая, безжалостная обратная связь категорически ПРИВЕТСВУЕТСЯ
  5. сейчас еще возник вопрос на счет разделения интерфейсов FileSystemAction, FileAction, DirectoryAction, кажется, что это избыточно и достаточно будет только одного интерфейса FileSystemAction, так ли это?
  6. правильно ли используется JavaDoc? Есть ли какие-либо рекомендации?

чтобы было проще разобраться (надеюсь на это) с тем, как классы и интерфейсы взаимодействуют составил UML диаграмму, ее можно найти в репозитории проекта проект на Гитхаб, либо я по ней задавал вопрос тут же на StackOverflow.

код программы:

package ex02;

import ex02.command.FileManager;

/**
 * Entry point for the file manager application.
 */
public class Program {
    /**
     * Main method to start the file manager.
     *
     * @param args command line arguments
     */
    public static void main(String[] args) {
        FileManager fm = new FileManager(args[0]);
        boolean exitProgram = false;
        while (!exitProgram) {
            exitProgram = fm.isExitFileManager();
        }
    }
}

package ex02.command;

import java.nio.file.Path;
import java.util.Scanner;

import ex02.interfaces.FileSystemAction;

/**
 * Manages the current working directory and file operations.
 */
public class FileManager {
    private Scanner scanner = new Scanner(System.in);
    /**
     * Current path.
     */
    private Path pwdPath;

    /**
     * Validate and get user command.
     * 
     * @return string array splited by whitespace
     */
    private String[] getUserCommand() {
        return CommandHandler.getCommand(scanner.nextLine());
    }

    /**
     * Constructs a FileManager with the given initial working directory.
     *
     * @param pwd the initial working directory
     */
    public FileManager(final String pwd) {
        pwdPath = CommandHandler.getValidatedPath(pwd);
        System.out.println(pwdPath.toString());
    }

    /**
     * Starts the file manager command loop, processing user commands
     * until the exit command is received.
     *
     * @return true if exit command was received, false otherwise
     */
    public boolean isExitFileManager() {
        String[] userCommand = getUserCommand();
        boolean exitCommand = userCommand.length > 0 ? userCommand[0].equals("exit") : Boolean.getBoolean("false");

        while (!exitCommand) {
            try {
                FileSystemAction fsAction = CommandHandler.getActionType(userCommand);
                fsAction.action(this, userCommand);
            } catch (RuntimeException e) {
                System.out.println(e.toString());
                for (StackTraceElement elem : e.getStackTrace()) {
                    System.out.println("         --- " + elem.toString());
                }
                return exitCommand;
            }
            userCommand = getUserCommand();
            exitCommand = userCommand[0].equals("exit");
        }
        return exitCommand;
    }

    /**
     * Gets the current working directory path.
     *
     * @return the current path
     */
    public Path getPwdPath() {
        return pwdPath;
    }

    /**
     * Sets the current working directory path.
     *
     * @param path the new path
     */
    public void setPwdPath(Path path) {
        this.pwdPath = path;
    }
}

package ex02.command;

import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.util.Map;

import ex02.directory.DirectoryInfoProvider;
import ex02.directory.WorkDirectoryChanger;
import ex02.file.FileReplacer;
import ex02.interfaces.CommandValidator;
import ex02.interfaces.FileSystemAction;

/**
 * Handles parsing, validation, and execution of file manager commands.
 */
public class CommandHandler {
    /**
     * Validates command args.
     */
    private static Map<String, CommandValidator> validators = Map.of(
            "ls", args -> {
                if (args.length != 1) {
                    throw new UnsupportedOperationException("ls - does not accept arguments");
                }
            },
            "mv", args -> {
                if (args.length != 3) {
                    throw new UnsupportedOperationException("mv - the source and destination paths are needed");
                }
            },
            "cd", args -> {
                if (args.length != 2) {
                    throw new UnsupportedOperationException("cd - one argument is needed, destination directiry");
                }
            },
            "", args -> {
                throw new UnsupportedOperationException("you need to select one of the commands: mv, cd, ls");
            });

    /**
     * Supported operations.
     */
    private static Map<String, FileSystemAction> commands = Map.of(
            "ls", new DirectoryInfoProvider(),
            "mv", new FileReplacer(),
            "cd", new WorkDirectoryChanger());

    private CommandHandler() {
        throw new UnsupportedOperationException("Utility class!");
    }

    public static String[] getCommand(String input) {
        if (input.isEmpty()) {
            System.out.println("Enter a command \"ls\" or \"cd\" or \"mv\"");
            return new String[] {};
        } else {
            return input.split(" ");
        }
    }

    private static Path validatePwdPath(final String path) {
        Path pwdPath = Path.of(path.replace("--current-folder=", ""));

        if (Files.isDirectory(pwdPath, LinkOption.NOFOLLOW_LINKS)) {
            return pwdPath;
        } else {
            throw new IllegalArgumentException("Path does not exist"
                    + " оr not a directiry");
        }
    }

    public static Path getValidatedPath(final String path) {
        return validatePwdPath(path);
    }

    public static Path getValidatedPath(final Path path) {
        return validatePwdPath(path.toString());
    }

    public static FileSystemAction getActionType(String[] args) throws UnsupportedOperationException {
        FileSystemAction actionType = null;

        if (args.length > 0) {
            validators.get(args[0]).validate(args);
            actionType = commands.get(args[0]);
        }

        if (actionType == null) {
            throw new UnsupportedOperationException(
                    """
                            This type of operation does not support!
                            """);
        }

        return actionType;
    }
}

package ex02.interfaces;

import ex02.command.FileManager;

/**
 * Interface for actions related to the file system.
 */
public interface FileSystemAction {
    /**
     * Performs an action on the file system.
     *
     * @param fileManager the file manager instance
     * @param command     the command arguments
     */
    void action(FileManager fileManager, String[] command);
}

package ex02.interfaces;

import ex02.command.FileManager;

/**
 * Interface for actions related to directories.
 */
public interface DirectoryAction extends FileSystemAction {
    /**
     * Performs an action on a directory.
     *
     * @param fileManager the file manager instance
     * @param command     the command arguments
     */
    void action(FileManager fileManager, String[] command);
}

package ex02.interfaces;

import ex02.command.FileManager;

/**
 * Interface for actions related to files.
 */
public interface FileAction extends FileSystemAction {
    /**
     * Performs an action on a file.
     *
     * @param fileManager the file manager instance
     * @param command     the command arguments
     */
    void action(FileManager fileManager, String[] command);
}

package ex02.interfaces;

/**
 * Validates command arguments for file manager operations.
 */
public interface CommandValidator {
    /**
     * Validates the command arguments.
     *
     * @param args command arguments
     */
    void validate(String[] args);
}

package ex02.directory;

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;

import ex02.command.FileManager;
import ex02.interfaces.DirectoryAction;

/**
 * Provides information about the contents of a directory.
 */
public class DirectoryInfoProvider implements DirectoryAction {
    /**
     * Lists the contents of the current directory.
     *
     * @param fileManager the file manager instance
     * @param command     user command, do not use in this case
     */
    @Override
    public void action(FileManager fileManager, String[] command) {
        try (DirectoryStream<Path> ds = Files.newDirectoryStream(
                fileManager.getPwdPath())) {
            for (Path entry : ds) {
                long countOfBytes = Files.walk(entry)
                        .filter(Files::isRegularFile)
                        .mapToLong(x -> {
                            try {
                                return Files.size(x);
                            } catch (IOException e) {
                                return 0L;
                            }
                        })
                        .sum();
                System.out.println(entry.getName(entry.getNameCount() - 1)
                        + " "
                        + (countOfBytes > 1024 ? countOfBytes / 1024 : countOfBytes)
                        + " KB");
            }
        } catch (IOException e) {
            System.out.println(e.toString());
        }
    }
}

package ex02.directory;

import java.nio.file.Path;

import ex02.command.CommandHandler;
import ex02.command.FileManager;
import ex02.interfaces.DirectoryAction;

/**
 * Changes the current working directory in the file manager.
 */
public class WorkDirectoryChanger implements DirectoryAction {
    /**
     * Changes the current directory to the specified target.
     *
     * @param fileManager the file manager instance
     * @param command     the command arguments, where command[1] is the target
     *                    directory
     * @throws IllegalArgumentException if the target directory is invalid
     */
    @Override
    public void action(FileManager fileManager, String[] command)
            throws IllegalArgumentException {
        Path target = Path.of(command[1]);
        if (!target.isAbsolute()) {
            target = fileManager.getPwdPath().resolve(target);
        }
        fileManager.setPwdPath(CommandHandler.getValidatedPath(target).normalize());
        System.out.println(fileManager.getPwdPath());
    }
}

package ex02.file;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

import ex02.command.FileManager;
import ex02.interfaces.FileAction;

/**
 * Handles file move and rename operations.
 */
public class FileReplacer implements FileAction {
    /**
     * Moves or renames a file or directory.
     *
     * @param fileManager the file manager instance
     * @param command     which includes source (index 1) & destination (index 2)
     *                    paths
     */
    @Override
    public void action(final FileManager fileManager, final String[] command) {
        try {
            Path pwd = fileManager.getPwdPath();
            Path src = pwd.resolve(command[1]).toAbsolutePath().normalize();
            Path dst = pwd.resolve(command[2]).toAbsolutePath().normalize();

            if (!Files.exists(src)) {
                System.out.println("File not found!");
            }
            if (Files.isDirectory(dst, LinkOption.NOFOLLOW_LINKS)) {
                Files.move(src, dst.resolve(src.getFileName()),
                        StandardCopyOption.REPLACE_EXISTING);
            } else {
                Files.move(src, dst);
            }
        } catch (IOException e) {
            System.out.println(e.toString());
        }
    }
}

Ответы

Ответов пока нет.