7. Реализовать расширяемый сервис отправки уведомлений
Условие задачи:
Необходимо реализовать сервис Notificator, который отправляет сообщение через несколько внешних сервисов, например Email и SMS.
При добавлении нового канала уведомлений код Notificator не должен изменяться.
Код:
public class EmailNotificationService {
public void sendEmail(String message) {
System.out.println("Send from email service");
System.out.println(message);
}
}
public class SmsNotificationService {
public void sendSms(String message) {
System.out.println("Send from sms service");
System.out.println(message);
}
}
Спойлеры к решению
Подсказки
💡 Внешние библиотеки можно обернуть адаптерами.
💡 Spring умеет внедрять сразу
List всех бинов одного интерфейса.💡 Внешние сервисы также нужно зарегистрировать как Spring-бины.
💡 Для добавления нового канала достаточно создать новую реализацию интерфейса.
Решение
Общий интерфейс:
public interface NotificationService {
void send(String message);
}
Адаптер для Email:
@Service
public class EmailNotificationAdapter
implements NotificationService {
private final EmailNotificationService emailService;
public EmailNotificationAdapter(
EmailNotificationService emailService
) {
this.emailService = emailService;
}
@Override
public void send(String message) {
emailService.sendEmail(message);
}
}
Адаптер для SMS:
@Service
public class SmsNotificationAdapter
implements NotificationService {
private final SmsNotificationService smsService;
public SmsNotificationAdapter(
SmsNotificationService smsService
) {
this.smsService = smsService;
}
@Override
public void send(String message) {
smsService.sendSms(message);
}
}
Регистрация классов внешних библиотек:
@Configuration
public class NotificationConfiguration {
@Bean
public EmailNotificationService emailNotificationService() {
return new EmailNotificationService();
}
@Bean
public SmsNotificationService smsNotificationService() {
return new SmsNotificationService();
}
}
Сервис отправки уведомлений:
@Service
public class Notificator {
private final List<NotificationService> channels;
public Notificator(
List<NotificationService> channels
) {
this.channels = channels;
}
public void notifyAll(String message) {
for (NotificationService channel : channels) {
channel.send(message);
}
}
}
Spring автоматически передаст в List<NotificationService> все зарегистрированные реализации интерфейса.
Чтобы добавить новый канал, например Telegram, достаточно создать новый адаптер:
@Service
public class TelegramNotificationAdapter
implements NotificationService {
@Override
public void send(String message) {
// отправка сообщения
}
}
Изменять Notificator при этом не потребуется.
Здесь используется паттерн Adapter для приведения разных внешних API к общему интерфейсу и соблюдается принцип Open/Closed: систему можно расширять новыми каналами без изменения основной логики.