Существует ли шаблон проектирования, который поддерживает инъекции нескольких реализаций абстрактного класса и условно использует один из внедренных бинов - PullRequest
0 голосов
/ 20 февраля 2020

Я работаю над проектом, использующим Java и Spring Boot, который обрабатывает несколько разных типов сообщений из одной и той же очереди. Каждое сообщение обрабатывается в зависимости от типа сообщения с использованием реализации MessageProcessingService абстрактного класса для каждого типа сообщения.

На данный момент у нас 5 разных типов сообщений, приходящих к одному и тому же потребителю. Мы используем ту же очередь, потому что мы используем групповые политики в JMS, и каждый тип сообщения имеет тот же бизнес-ключ, что и групповая политика.

Итак, в итоге мы получаем, что каждый раз, когда требование требует получения нового к типу сообщения мы добавляем новую реализацию MessageProcessingService и другую зависимость к объекту-потребителю. Я хочу найти лучшую стратегию, чтобы выборочно выбирать обработку сообщений

Вот пример, аналогичный тому, что мы делаем. Я не гарантирую, что синтаксис является компилируемым или синтаксически совершенным, просто демонстрируя проблему. Обратите внимание, что все сообщения разрешаются вокруг человека

Потребитель:

@Component
public class PersonMessageConsumer {
  private MessageProcessingService<HeightUpdate> heightUpdateMessageProcessingService;
  private MessageProcessingService<WeightUpdate> weightUpdateMessageProcessingService;
  private MessageProcessingService<NameUpdate>   nameUpdateMessageProcessingService;
  private MessageProcessingService<ShowSizeUpdate> shoeSizeUpdateMessageProcessingService;

  public PersonMessageConsumer(
         MessageProcessingService<HeightUpdate> heightUpdateMessageProcessingService,
         MessageProcessingService<WeightUpdate> weightUpdateMessageProcessingService,
         MessageProcessingService<NameUpdate>   nameUpdateMessageProcessingService,
         MessageProcessingService<ShowSizeUpdate> shoeSizeUpdateMessageProcessingService) {

    this.heightUpdateMessageProcessingService = heightUpdateMessageProcessingService;
    this.weightUpdateMessageProcessingService = weightUpdateMessageProcessingService;
    this.nameUpdateMessageProcessingService = nameUpdateMessageProcessingService;
    this.shoeSizeUpdateMessageProcessingService = shoeSizeUpdateMessageProcessingService;
  }

  @JmsListener(destination = "${queueName}")
  public void receiveMessage(TextMessage message) {
    String messageType = message.getHeader("MessageType");
    switch (messageType) {
      case "HeightUpdate":
        heightUpdateMessageProcessingService.processMessage(message.getText());
        return;
      case "WeightUpdate":
        weightUpdateMessageProcessingServivce.processMessage(message.getText());
        return;
      // And other message types
      default: 
        throw new UnknownMessageTypeException(messageType);
  }
}

Пример сообщения POJO

public class HeightUpdate implements PersonMessage {
  @Getter
  @Setter
  private int height;
}

Интерфейс PersonMessage

public interface PersonMessage {
  int getPersonId();
}

MessageProcessingService

public abstract class MessageProcessingService<T extends PersonMessage> {

  public void processMessage(String messageText) {
    //Common message processing, we do some more involved work here but just as a simple example
    T message = new ObjectMapper.readValue(messageText, getClassType());

    Person person = personRepository.load(message.getPersonId());
    Person originalPerson = person.deepCopy();
    processMessageLogic(person, message);

    if (originalPerson.isDifferentFrom(person)) { 
      personRespository.update(person);
    } 
  }

  protected abstract void processMessageLogic(Person person, T message);

  protected abstract Class getClassType();
}

Пример реализации абстрактного класса

@Service("heightUpdateMessageProcessingService")
public class HeightUpdateMessageProcessingService extends MessageProcessingService<HeightUpdate> {
  @Override
  protected void processMessageLogic(Person person, HeightUpdate update) {
    person.setHeight(update.getHeight());
  }

  @Override
  protected Class getMessageType() {
    return HeightUpdate.getClass();
  }
}

Так что мой вопрос в том, есть ли лучший шаблон проектирования или способ его кодирования в java и пружине, которая немного проще чистить и поддерживать и помнить SOLID принципы

1 Ответ

1 голос
/ 20 февраля 2020
  1. Добавьте абстрактный метод в MessageProcessingService для возврата messageType, который может обрабатывать каждая конкретная реализация.
  2. Вместо того, чтобы подключать каждую отдельную службу к PersonMessageConsumer, подключите к List<MessageProcessingService> чтобы вы могли получить их все сразу.
  3. Преобразуйте это List в Map<String, MessageProcessingService>, используя messageType в качестве ключа.
  4. Замените оператор switch на ищем соответствующий сервис в Map и затем вызываем его метод processMessage.

В будущем вы можете добавлять новые экземпляры MessageProcessingService без необходимости редактировать PersonMessageConsumer, потому что Spring будет автоматически добавляйте эти новые экземпляры в List<MessageProcessingService>, к которому вы подключаетесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...