Не могу правильно структурировать проект с большим количеством зависимостей на Java

Я делаю проект Java и столкнулся с серьезной проблемой. В моем проекте у меня много менеджеров и репозиториев. Я частично решил проблему, обратившись к классу MainApplication, который содержит все ссылки на репозитории и менеджеры, поэтому, обращаясь к нему, я могу без каких-либо усилий получить каждый нужный мне репозиторий. Упрощенный код выглядит так:

class MainApplication {
    private final UserRepository userRepository;
    private final GroupRepository groupRepository;
    private final PhotoRegistry photoRegistry;
    private final UserDAO userDAO;

    public MainApplication() {
        this.userRepository = new UserRepository(this);
        this.groupRepository = new GroupRepository(this);
        this.photoRegistry = new PhotoRegistry();
        this.userDAO = new UserDAO();
    }

    public UserRepository getUserRepository() {
        return userRepository;
    }

    public GroupRepository getGroupRepository() {
        return groupRepository;
    }

    public PhotoRegistry getPhotoRegistry() {
        return photoRegistry;
    }



    public UserDAO getUserDAO() {
        return userDAO;
    }
}


interface ResponseHandler {

    void handleResponse(User user, String response);

}

class User {

    private final long id;
    private final long groupId;
    private ResponseHandler responseHandler;
    private UserRepository repository;

    public User (long id, long groupId, UserRepository repository) {
        this.id = id;
        this.groupId = groupId;
        this.repository = repository;
    }

    public void processResponse(String response) {
        if (this.responseHandler != null) responseHandler.handleResponse(this, response);
    }

    public void reply(String replyText, byte [] photo) {
        // some reply logic
    }

    public void setResponseHandler(ResponseHandler handler) {
        this.responseHandler = handler;
    }

    public UserRepository getRepository() {
        return repository;
    }

    public long getGroupId() {
        return groupId;
    }

    public long getId() {
        return id;
    }
}

class Group {
    private long id;
    private String groupDescription;


    public String getDescription() {
        return groupDescription;
    }
    public long getId() {
        return id;
    }

}

class UserRepository {
    private final MainApplication main;
    private final Map<Long, User> users;


    public UserRepository(MainApplication main) {
        this.main = main;
        this.users = new HashMap<>();
    }

    public User createUser(long userId, long groupId) {
        User newUser = new User(userId, groupId, this);
        this.users.put(newUser.getId(), newUser);
        return newUser;
    }

    public User getUser(long id) {
        return users.get(id);
    }


    public MainApplication getMain() {
        return main;
    }
}

class GroupRepository {
    private final MainApplication main;
    private final Map<Long, Group> groups;



    public GroupRepository(MainApplication main) {
        this.main = main;
        this.groups = new HashMap<>();
    }

    public void addGroup(Group group) {
        this.groups.put(group.getId(), group);
    }

    public Group getGroup(long id) {
        return groups.get(id);
    }


}

class PhotoRegistry {

    private final Map<String, byte[]> photosToName;

    public PhotoRegistry() {
        this.photosToName = new HashMap<>();
    }


    public void registerPhoto(String photoName, byte[] data) {
        this.photosToName.put(photoName, data);
    }


    public byte[] getPhoto(String photoName) {
        return photosToName.get(photoName);
    }
}



class UserDAO {
  
    public double getBalanceFor(long userId) {
        double balance = 0;
        // retrieving balance from database
        return balance;
    }

}

и вот простое использование приведенного выше кода:

class Main {

    public static void main(String[] args) {
        //registering the application
        MainApplication main = new MainApplication();

        User user = main.getUserRepository().createUser(0, 1);

        ResponseHandler handler = new ResponseHandler() {
            @Override
            public void handleResponse(User user, String response) {

                if (!response.equalsIgnoreCase("Hello")) return;
                
                
                MainApplication main = user.getRepository().getMain();

                double userBalance = main.getUserDAO().getBalanceFor(user.getId());
                Group userGroup = main.getGroupRepository().getGroup(user.getGroupId());
                byte [] attachedPhoto = main.getPhotoRegistry().getPhoto("balancePhoto");


                StringBuilder builder = new StringBuilder();
                builder.append("Hello user ")
                        .append(user.getId())
                        .append("\n")
                        .append("You are in a group with id: ")
                        .append(userGroup.getId())
                        .append(" and description: ")
                        .append(userGroup.getDescription())
                        .append("your balance is $")
                        .append(userBalance);


                user.reply(builder.toString(), attachedPhoto);
            }
        };
        
        user.setResponseHandler(handler);
        
        
        // supplying a response from user
        user.processResponse("Hello");
        
        
    }
}

Итак, мой вопрос: как мне лучше структурировать этот проект? Нужно ли мне использовать среду внедрения зависимостей, например Spring или Guice? На мой взгляд, это можно сделать гораздо лучше, но я понятия не имею, как это сделать, потому что не могу точно предсказать, какие репозитории или менеджеры мне понадобятся в реализации ResponseHandler.

Я уже пробовал использовать Guice, но не совсем понимаю, как он сюда подходит. Также я старался предоставлять только необходимые ссылки на UserRepository вместо передачи всего экземпляра MainApplication, но в моем проекте гораздо больше репозиториев, чем в этом, поэтому конструктор становится действительно огромным, и с ним нелегко работать.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
81
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итак, мой вопрос: как мне лучше структурировать этот проект?

О структуре программ и архитектуре программного обеспечения написаны целые книги (например, APPP , PEAA), поэтому мы не можем легко ответить на этот вопрос, основываясь на небольшом примере. Тем не менее, вам следует стараться избегать циклических зависимостей, поскольку это обязательно сделает ваш код более сложным, чем он должен быть.

Например, MainApplication, очевидно, зависит от UserRepository, но UserRepository также зависит от MainApplication. Похоже, то же самое и с GroupRepository.

По моему опыту, вам никогда не понадобятся циклические зависимости. В APPP Роберт К. Мартин называет это принципом ациклических зависимостей (ADP) (глава 28).

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

Нужно ли мне использовать среду внедрения зависимостей, например Spring или Guice?

Нет, вам не нужен DI-контейнер, чтобы воспользоваться преимуществами внедрения зависимостей.

Другие вопросы по теме