Как правильно структурировать многомодульный проект?

Это было то, с чем я всегда боролся, когда начинал новые проекты. Поэтому я решил спросить здесь и посмотреть, что, по вашему мнению, было бы лучшим способом структурировать этот проект, и, надеюсь, я чему-то научился из этого.

Это основное описание проекта (кстати, я использую Gradle и пишу на Java).

Мне нужно сделать плагин, который работает на нескольких платформах, например Spigot, Bungeecord и Velocity, у всех трех есть собственные API, которые мне нужно использовать, чтобы плагин работал с каждой платформой. И проект представляет собой плагин диктора, который позволяет пользователям настраивать настраиваемых дикторов, которые будут отправлять сообщения игрокам, подключенным к этим серверам.

Мой общий мыслительный процесс состоял в том, чтобы сделать:

  1. общий модуль: где будет храниться большая часть логики, которая может быть применена к другим трем модулям.
  2. Модуль spigot: используя логику, формируйте общий модуль и формируйте его так, чтобы spigot мог его понять.
  3. модуль bungeecord: используя логику, формируйте общий модуль и формируйте его так, чтобы bungeecord мог его понять.
  4. модуль скорости: используя логику, формируем общий модуль и формируем его так, чтобы скорость могла его понять.

Некоторые из вещей, которые должны быть в проекте:

  • Основной класс плагина, который имеет логику загрузки и включения плагина (каждый API имеет свой собственный класс, который расширяет основной класс для запуска плагинов).
  • Класс управления файлами, который будет загружать конфигурацию из файлов yaml, таких как сообщения для дикторов, общие настройки (у каждого API есть свой класс для чтения файлов yaml).
  • Создатель диктора и классы обработки, которые будут читать файл конфигурации диктора, используя классы управления файлами, и создавать дикторов как объект и обработчик, который будет отправлять его игроку и т. д. (у каждого API есть свой способ взаимодействия с игроками).
  • Система команд, которая имеет логику для команд, которые будут выполняться пользователями и игроками (каждый API имеет свою собственную логику для обработки команд).

Итак, мой вопрос: как бы вы структурировали этот проект с наименьшим количеством повторяемого кода, дублируя классы, которые в основном делают одно и то же, только немного по-разному для каждого API, и сохраняя при этом хорошую читаемость кода?

Сейчас у меня есть рабочая версия для Spigot, но она превратилась в полный беспорядок, когда я начал добавлять поддержку Bungeecord.

EDIT: пример одной из наиболее распространенных проблем, с которыми я сталкиваюсь:

Spigot API имеет Bukkit класс с getServer() методом, который возвращает Server объект. Bungeecord API имеет ProxiedServer класс с getInstance() методом, возвращающим ProxiedServer объект.

А у меня что-то вроде этого:

public interface MyPlugin {

    ? getServer();
}

//extends JavaPlugin is required by Spigot API.
public class SpigotPlugin extends JavaPlugin implements MyPlugin {
    
    @Overrride
    public ? getServer() {
        return Bukkit.getServer();
    }
}

//extends Plugin is required by Bungeecord API.
public class BungeeCordPlugin extends Plugin implements MyPlugin {
 
    @Overrride
    public ? getServer() {
        return ProxiedServer.getInstance();
    }
}

Что нужно поставить вместо ?, чтобы получить правильный экземпляр сервера (я не могу редактировать классы ProxiedServer или Bukkit)?


person Lynx    schedule 25.11.2020    source источник
comment
Пронумерованные элементы звучат как хорошее начало для модулей, где от 2 до 4 — вертикальные срезы. Я не уверен, что означает полный беспорядок, но шаблон адаптера может помочь. Не должно быть повторяющегося кода.   -  person Andrew S    schedule 26.11.2020
comment
Под беспорядком я подразумеваю, что у меня есть методы, которые принимают Object в качестве параметра, а затем приводят его к требуемому объекту в зависимости от платформы, на которой работает плагин, поэтому в результате получается много кастингов. Мне не очень нравится такой подход, и я не уверен, что так и должно быть. Я проверю шаблон адаптера, спасибо за предложение.   -  person Lynx    schedule 26.11.2020
comment
Вот где шаблон адаптера может быть полезен. Общий класс обернут классом, специфичным для платформы. Класс платформы знает, как взаимодействовать со своей платформой, но использует общий класс для получения данных.   -  person Andrew S    schedule 26.11.2020


Ответы (1)


Этому несколько месяцев, но в интересах архивов и будущих искателей я хотел бы предложить следующее: Да, вы можете вернуть общий тип примерно так:

@Overrride
public <T> getServer() {
    return plugin.getInstance();
}

Для справки: https://stackoverflow.com/a/31239655/10793514

И дополнительная информация о дженериках: https://www.baeldung.com/java-generics#generic-methods

person Richard Simpson    schedule 17.03.2021