- 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
9.1 KiB
9.1 KiB
🔧 Рефакторинг сервисов - уменьшение количества файлов
Текущая ситуация
- 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 - это самое простое объединение:
- PM, Spy, Ignore логически связаны (общение между игроками)
- Все три сервиса маленькие (28-97 строк)
- Объединение даст ~200 строк - нормальный размер
Потом ModerationService - это сложнее:
- Mute + Punishment + History = ~460 строк
- Нужно будет рефакторить внутреннюю структуру
- Но логически это одна область (модерация)
PlayerService оставь на потом - там всё норм.
📝 Итого
Объединение сервисов:
- ✅ Уменьшит количество файлов с 23 до 15
- ✅ Упростит навигацию по коду
- ✅ Сгруппирует связанную функциональность
- ⚠️ Потребует обновления кода, который использует старые сервисы
Начни с MessagingService - это быстро и безопасно.