Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Service as "Factory" to Return Different Bean Implementations

I want to use this type of service class in my Spring application as a "factory" to return the correct implementation of DocumentProcessor in response to a supplied enum value.

I'm doing this because I want to set up each processor itself as a component and take advantage of autowiring vs just creating new instances when each processor is needed.

I haven't really seen this done anywhere else - Can anyone tell me if this is a bad idea?

All "TypeXYZDocumentProcessor" classes are extensions of an abstract "DocumentProcessor" base class.

@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 {
  ...
}
like image 950
alexp3y Avatar asked Dec 17 '25 19:12

alexp3y


2 Answers

This is my proposition, I used Interface instead of abstract class, but if you really need an abstract class you can return on it.

@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 {
  ...
}
like image 84
medkhelifi Avatar answered Dec 19 '25 12:12

medkhelifi


You may also do something like this. I've modified your abstract class DocumentProcessor to include the DocumentType. Code is not tested or compiled.

This way, you can keep introducing more processors types and not touch the processor service at all.

@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;

  }
}
like image 35
Neo Avatar answered Dec 19 '25 11:12

Neo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!