LoChat/REFACTORING_SERVICES.md
loki5512344 bba480002f refactor: restructure services and filters architecture
- Remove deprecated service interfaces (CooldownService, IgnoreService, PMService, PlayerDataService, SpyService)
- Add new unified service interfaces (MessagingService, PlayerService, PunishmentService)
- Extract FilterResult as standalone class from AdvancedMessageFilter
- Implement individual filter classes (CharacterFilter, FloodFilter, SpamFilter, SwearFilter, UrlFilter)
- Add moderation commands (BanCommand, WarnCommand, SilentWarnCommand, UnbanCommand)
- Introduce data models for punishment tracking (BanRecord, WarnEntry)
- Refactor messaging service with new MessagingServiceImpl implementation
- Add mute service utilities (MuteDataStorage, MutePermissionChecker)
- Implement PunishmentServiceImpl with snapshot tracking
- Add Discord integration components (DiscordConfig, DiscordMessageService)
- Introduce command handlers for gradient module (ColorCommandHandler, PrefixCommandHandler)
- Add renderer components (EmojiComponent, GradientBuilder, UrlProcessor)
- Add utility classes (ColorConverter, MessageSender, PlaceholderProcessor)
- Update configuration files and plugin metadata
- Add documentation files (CODE_REVIEW_RU.md, REFACTORING_SERVICES.md)
- Consolidate service architecture for improved maintainability and separation of concerns
2026-04-06 00:18:25 +02:00

9.1 KiB
Raw Blame History

🔧 Рефакторинг сервисов - уменьшение количества файлов

Текущая ситуация

  • 11 интерфейсов в api/service/
  • 12 реализаций в core/service/
  • 23 файла только для сервисов
  • Некоторые сервисы по 30 строк кода

Проблема

Слишком много мелких файлов, которые можно объединить по функциональности.


🎯 План рефакторинга

1. Объединить простые сервисы в один

Было:

PMService.java (28 строк)
SpyService.java (69 строк)
IgnoreService.java (97 строк)

Станет:

// MessagingService.java - всё что связано с общением
public interface MessagingService {
    // PM
    void setLastConversation(UUID sender, UUID receiver);
    UUID getLastConversation(UUID player);
    
    // Spy
    boolean toggleSpy(UUID player);
    boolean isSpying(UUID player);
    void broadcastPM(Player sender, Player receiver, String message);
    
    // Ignore
    void addIgnore(UUID player, UUID target);
    void removeIgnore(UUID player, UUID target);
    boolean isIgnoring(UUID player, UUID target);
    Set<UUID> getIgnoreList(UUID player);
}

Экономия: 3 интерфейса + 3 реализации = 6 файлов → 2 файла


2. Объединить Mute + Punishment

Было:

MuteService.java + MuteServiceImpl.java (212 строк)
PunishmentService.java + PunishmentServiceImpl.java (173 строки)
MuteHistoryManager.java (77 строк)

Станет:

// ModerationService.java - всё что связано с модерацией
public interface ModerationService {
    // Mutes
    void mute(UUID uuid, String name, long duration, String reason, String by);
    boolean unmute(UUID uuid, String by);
    boolean isMuted(UUID uuid);
    MuteData getMuteData(UUID uuid);
    
    // Bans
    void ban(UUID uuid, String name, long duration, String reason, String by);
    boolean unban(UUID uuid, String by);
    boolean isBanned(UUID uuid);
    BanData getBanData(UUID uuid);
    
    // Warns
    void warn(UUID uuid, String name, String reason, String by);
    List<WarnData> getWarns(UUID uuid);
    
    // History
    List<ModerationEntry> getHistory(UUID uuid);
    List<ModerationEntry> getHistoryByModerator(String name);
}

Экономия: 3 интерфейса + 3 реализации = 6 файлов → 2 файла


3. Объединить Cooldown + PlayerData

Было:

CooldownService.java + CooldownServiceImpl.java (40 строк)
PlayerDataService.java + PlayerDataServiceImpl.java (102 строки)

Станет:

// PlayerService.java - всё что связано с данными игрока
public interface PlayerService {
    // Cooldowns
    boolean hasCooldown(UUID player, String type);
    void setCooldown(UUID player, String type, long duration);
    long getRemainingCooldown(UUID player, String type);
    void clearCooldowns(UUID player);
    
    // Statistics
    void recordMessage(UUID player, String chatType);
    PlayerStats getStats(UUID player);
    void saveAll();
}

Экономия: 2 интерфейса + 2 реализации = 4 файла → 2 файла


4. Оставить как есть (нормальный размер)

ChatService.java + ChatServiceImpl.java (114 строк) ✅
MessageService.java + MessageServiceImpl.java (36 строк) ✅
MentionService.java + MentionServiceImpl.java (104 строки) ✅
NickService.java + NickServiceImpl.java (155 строк) ✅

Эти сервисы имеют чёткую ответственность и нормальный размер.


📊 Результат рефакторинга

До После Экономия
11 интерфейсов 7 интерфейсов -4
12 реализаций 8 реализаций -4
23 файла 15 файлов -8 файлов

🔨 Пошаговая реализация

Шаг 1: Создать MessagingService

// api/service/MessagingService.java
public interface MessagingService {
    // PM
    void setLastConversation(UUID sender, UUID receiver);
    UUID getLastConversation(UUID player);
    
    // Spy
    boolean toggleSpy(UUID player);
    boolean isSpying(UUID player);
    void broadcastPM(Player sender, Player receiver, String message);
    void sendToSpies(Player sender, Component message, boolean isGlobal);
    void removeSpy(UUID player);
    
    // Ignore
    void addIgnore(UUID player, UUID target);
    void removeIgnore(UUID player, UUID target);
    boolean isIgnoring(UUID player, UUID target);
    Set<UUID> getIgnoreList(UUID player);
    void save();
}

// core/service/MessagingServiceImpl.java
public class MessagingServiceImpl implements MessagingService {
    private final JavaPlugin plugin;
    private final MessageConfig messageConfig;
    
    // PM state
    private final Map<UUID, UUID> lastConversation = new ConcurrentHashMap<>();
    
    // Spy state
    private final Set<UUID> spyEnabled = ConcurrentHashMap.newKeySet();
    
    // Ignore state
    private final Map<UUID, Set<UUID>> ignoreMap = new ConcurrentHashMap<>();
    
    public MessagingServiceImpl(JavaPlugin plugin, MessageConfig messageConfig) {
        this.plugin = plugin;
        this.messageConfig = messageConfig;
        loadIgnoreData();
    }
    
    // Реализация всех методов...
}

Шаг 2: Обновить ServiceRegistry

// Было
register(PMService.class, new PMServiceImpl());
register(SpyService.class, new SpyServiceImpl(messageConfig));
register(IgnoreService.class, new IgnoreServiceImpl(plugin));

// Стало
MessagingService messaging = new MessagingServiceImpl(plugin, messageConfig);
register(MessagingService.class, messaging);

// Для обратной совместимости (опционально)
register(PMService.class, messaging);
register(SpyService.class, messaging);
register(IgnoreService.class, messaging);

Шаг 3: Удалить старые файлы

# Удалить интерфейсы
rm src/main/java/com/loki/lochat/api/service/PMService.java
rm src/main/java/com/loki/lochat/api/service/SpyService.java
rm src/main/java/com/loki/lochat/api/service/IgnoreService.java

# Удалить реализации
rm src/main/java/com/loki/lochat/core/service/PMServiceImpl.java
rm src/main/java/com/loki/lochat/core/service/SpyServiceImpl.java
rm src/main/java/com/loki/lochat/core/service/IgnoreServiceImpl.java

⚠️ Альтернативный подход (если не хочешь ломать API)

Можно оставить старые интерфейсы, но сделать их делегатами:

// Старый интерфейс остаётся
public interface PMService {
    void setLastConversation(UUID sender, UUID receiver);
    UUID getLastConversation(UUID player);
}

// Но реализация делегирует в MessagingService
public class PMServiceAdapter implements PMService {
    private final MessagingService messaging;
    
    public PMServiceAdapter(MessagingService messaging) {
        this.messaging = messaging;
    }
    
    @Override
    public void setLastConversation(UUID sender, UUID receiver) {
        messaging.setLastConversation(sender, receiver);
    }
    
    @Override
    public UUID getLastConversation(UUID player) {
        return messaging.getLastConversation(player);
    }
}

Это позволит:

  • Сохранить обратную совместимость
  • Уменьшить количество реализаций (3 → 1)
  • Постепенно мигрировать код на новый API

🎯 Рекомендация

Начни с MessagingService - это самое простое объединение:

  1. PM, Spy, Ignore логически связаны (общение между игроками)
  2. Все три сервиса маленькие (28-97 строк)
  3. Объединение даст ~200 строк - нормальный размер

Потом ModerationService - это сложнее:

  1. Mute + Punishment + History = ~460 строк
  2. Нужно будет рефакторить внутреннюю структуру
  3. Но логически это одна область (модерация)

PlayerService оставь на потом - там всё норм.


📝 Итого

Объединение сервисов:

  • ✅ Уменьшит количество файлов с 23 до 15
  • ✅ Упростит навигацию по коду
  • ✅ Сгруппирует связанную функциональность
  • ⚠️ Потребует обновления кода, который использует старые сервисы

Начни с MessagingService - это быстро и безопасно.