Использование сервиса как «фабрики» для возврата различных реализаций бина - PullRequest
0 голосов
/ 21 декабря 2018

Я хочу использовать этот тип класса обслуживания в своем приложении Spring как "фабрику", чтобы вернуть правильную реализацию DocumentProcessor в ответ на предоставленное значение перечисления.

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

На самом деле я не видел, чтобы это делалось где-либо еще - может кто-нибудь сказать мне, если этоплохая идея?

Все классы "TypeXYZDocumentProcessor" являются расширениями абстрактного базового класса "DocumentProcessor".

@Service
public class DocumentProcessorService {

  @Autowired
  TypeXDocumentProcessor typeXDocumentProcessor;

  @Autowired
  TypeYDocumentProcessor typeYDocumentProcessor;

  @Autowired
  TypeZDocumentProcessor typeZDocumentProcessor;

  public DocumentProcessor getDocumentProcessor(DocumentType docType) {
    switch (docType) {
      case TYPE_X:
        return typeXDocumentProcessor;
      case TYPE_Y:
        return typeYDocumentProcessor;
      case TYPE_Z:
        return typeZDocumentProcessor;
      default:
        return null;
    }
  }
}  

@Component
public class TypeXDocumentProcessor extends DocumentProcessor {
  ...
}

public abstract class DocumentProcessor {
  ...
}

Ответы [ 3 ]

0 голосов
/ 21 декабря 2018

Это мое предложение, я использовал Interface вместо абстрактного класса, но если вам действительно нужен абстрактный класс, вы можете вернуться к нему.

@Service
public class DocumentProcessorService {

  @Autowired
  // you can add here for examlpe a @Qualifier("typeXDocumentProcessor"),
  // then name your variable whatever you want.
  DocumentProcessor typeXDocumentProcessor;

  @Autowired
  DocumentProcessor typeYDocumentProcessor;

  @Autowired
  DocumentProcessor typeZDocumentProcessor;

  public DocumentProcessor getDocumentProcessor(DocumentType docType) {
    switch (docType) {
      case TYPE_X:
        return typeXDocumentProcessor;
      case TYPE_Y:
        return typeYDocumentProcessor;
      case TYPE_Z:
        return typeZDocumentProcessor;
      default:
        return null;
    }
  }
}  

@Component
public class TypeXDocumentProcessor implements DocumentProcessor {
  ...
}
@Component
public class TypeYDocumentProcessor implements DocumentProcessor {
  ...
}
@Component
public class TypeZDocumentProcessor implements DocumentProcessor {
  ...
}

public interface class DocumentProcessor {
  ...
}
0 голосов
/ 22 декабря 2018

Вы также можете сделать что-то подобное.Я изменил ваш абстрактный класс DocumentProcessor, чтобы включить DocumentType.Код не тестируется и не компилируется.

Таким образом, вы можете продолжать вводить больше типов процессоров и вообще не трогать сервис процессоров.

@Service
public class DocumentProcessorService {

  @Autowired
  List<DocumentProcessor> documentProcessors;

  public DocumentProcessor getDocumentProcessor(DocumentType docType) {
    return documentProcessors.stream().filter(e -> e.getDocType().equals(docType)).findFirst().get();
  }
}

@Component
public class TypeXDocumentProcessor extends DocumentProcessor {

  public TypeXDocumentProcessor() {
    super(TYPE_X);
  }
}

// More Types...

public abstract class DocumentProcessor {
  ...

  DocumentType docType; 

  public DocumentProcessor(DocumentType docType) {
    this.docType = docType;
  }
  DocumentType getDocType() {
    return docType;

  }
}
0 голосов
/ 21 декабря 2018

Я предлагаю пойти другим путем.Давайте заменим блоки switch или if полиморфизмом (не проверено):

public enum DocumentType {

    TYPE_X("typeXDocumentProcessor"),
    TYPE_y("typeYDocumentProcessor");

    private DocumentProcessor processor;
    private final String beanName;

    DocumentType (String beanName){
      this.beanName = beanName;
    }
    public String process(){
        return processor.process();
    }


    @Component
    public static class DocumentTypeInjector {
        @Autowired
        private ApplicationContext context;

        @PostConstruct
        public void postConstruct() {
            for (DocumentType dt : EnumSet.allOf(DocumentType.class))
               dt.processor = context.getBean(dt.beanName)
        }
    }
}

И тогда вашему сервису вообще не понадобится метод getDocumentProcessor.Например, у вас был бы метод process, вызывающий process текущего экземпляра enum

...