Шаблон проектирования - Publisher/Subscriber в Java
- Шаблон Publisher/Subscriber
- Преймущества
- Пример применения
- Вывод
Содержание
Шаблон проектирования publisher/subscriber
Шаблон проектирования
издатель/подписчик
, также известный как шаблонпубликации/подписки
, представляет собой шаблон обмена сообщениями, в котором издатели отправляют сообщения подписчикам, не зная, кто эти подписчики. Шаблонpub/sub
часто используется в распределенных системах и архитектурах, управляемых событиями.
В Java шаблон pub/sub
может быть реализован с использованием шаблона Observer
, который представляет собой поведенческий шаблон, в котором объект поддерживает список наблюдателей, и автоматически уведомляет их о любых изменениях своего состояния.
Шаблон публикации/подписки также может быть реализован с использованием шаблона Reactor, который представляет собой шаблон параллелизма, в котором реактор обрабатывает и отправляет события или сообщения подписчикам.
Давайте рассмотрим пример реализации шаблона pub/sub
в Java с использованием шаблона Observer
.
Начнем с интерфейса, задача которого - получать сообщения.
@FunctionalInterface
public interface Subscriber<T> {
void receive(T message);
}
И реализуем его поведение:
public record ChatUser<T>(String name) implements Subscriber<T> {
@Override
public void receive(T message) {
System.out.println("user '" + name + "' received message: " + message);
}
}
Определим интерфейс, описывающий контракт для публикации сообщения и оповещения подписчиков.
public interface Publisher<T> {
void addSubscriber(Subscriber<T> subscriber);
void removeSubscriber(Subscriber<T> subscriber);
void notifySubscribers(T message);
}
Реализуем интерфейс ChatRoom
@FunctionalInterface
public interface ChatRoom<T> {
void sendMessage(T message);
}
И напишем его реализацию
public class SimpleChatRoom<T> implements ChatRoom<T>, Publisher<T>{
private final List<Subscriber<T>> subscribers = new ArrayList<>();
@Override
public void addSubscriber(final Subscriber<T> subscriber) {
Objects.requireNonNull(subscriber, "subscriber must not be null");
subscribers.add(subscriber);
}
@Override
public void removeSubscriber(final Subscriber<T> subscriber) {
if (Objects.isNull(subscriber)) {
return;
}
subscribers.remove(subscriber);
}
@Override
public void notifySubscribers(final T message) {
if (Objects.isNull(message)) {
return;
}
subscribers.forEach(sub -> sub.receive(message));
}
@Override
public void sendMessage(T message) {
notifySubscribers(message);
}
}
Протестируем нашу реализацию паттерна:
public class ChatRoomTest {
public static void main(String[] args) {
var chatRoom = new SimpleChatRoom<String>();
var alice = new ChatUser<String>("Alice");
var bob = new ChatUser<String>("Bob");
var charlie = new ChatUser<String>("Charlie");
chatRoom.addSubscriber(alice);
chatRoom.addSubscriber(bob);
chatRoom.addSubscriber(charlie);
chatRoom.sendMessage("Hello, everyone!");
chatRoom.removeSubscriber(bob);
chatRoom.sendMessage("Goodbye, Bob!");
chatRoom.removeSubscriber(charlie);
chatRoom.sendMessage("Goodbye, Charlie!");
}
}
Шаблон проектирования издатель/подписчик, представляет собой мощный шаблон обмена сообщениями, позволяющий отделить компоненты в системе. Он обычно используется в управляемых событиями архитектурах и распределенных системах. Этот шаблон допускает несвязанную архитектуру, в которой издатели и подписчики могут быть добавлены или удалены, не затрагивая остальную часть системы. Он также обеспечивает асинхронную связь, при которой издатели и подписчики могут работать независимо, не дожидаясь ответа друг от друга.