Шаблон проектирования - Publisher/Subscriber в Java

Cover Image for Шаблон проектирования - 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!");  
  }  
}

Шаблон проектирования издатель/подписчик, представляет собой мощный шаблон обмена сообщениями, позволяющий отделить компоненты в системе. Он обычно используется в управляемых событиями архитектурах и распределенных системах. Этот шаблон допускает несвязанную архитектуру, в которой издатели и подписчики могут быть добавлены или удалены, не затрагивая остальную часть системы. Он также обеспечивает асинхронную связь, при которой издатели и подписчики могут работать независимо, не дожидаясь ответа друг от друга.

Возникли вопросы по статье, не работает код, хотелось бы больше информации - свяжитесь с нами и мы поможем