How to delegate services by class type?

I have different types of classes, and depending on some conditions, I want to delegate the corresponding service , which can handle these types of classes.

Example: I have several classes as follows.

 class Student; class Prof; ... 

For each class there is a service that implements:

 interface IPersonService { void run(); } 

And I have mode , which is determined by some conditions:

 enum PersonType { STUDENT, PROF; } 

When I delegate:

 @Autowired private StudentService studentService; @Autowired private ProfService profService; //@param mode assume known public void delegate(PersonType mode) { //assume there are several of those switch statements in my business code switch (mode) { case STUDENT: studentService.run(); break; case PROF: profService.run(); break; default: break; } } 

Problem . When introducing additional classes, I need to change both PersonType and add an additional enumeration (this is not a problem), but I also need to extend any switch and add calls to additional delegation services. In addition, I must explicitly transfer these services to the delegate list.

Question : how can I optimize this code, just introduce new services for any additional class and not touch any of the switch statements?

+6
source share
3 answers

Add the IPersonService method IPersonService that the method implementation can tell the program what type of people it is accessing:

 interface IPersonService { PersonType supportedPersonType(); void run(); } 

In the service that performs the delegation, enter List<IPersonService> , which Spring will populate with all the IPersonService implementations that it can find. Then we implement the delegate method to scan the list to find the first IPersonService that can handle a specific type.

 @Autowired private List<IPersonService> personServices; public void delegate(PersonType mode) { for (IPersonService personService : personServices) { if (personService.supportedPersonType().equals(mode)) { personService.run(); break; } } } 

This way you can add new implementations of IPersonService without having to change the service that performs the delegation.

To avoid having to loop through each time a delegate is called, you can create a Map in advance so that you can quickly find the correct IPersonService :

 class DelegatingService { @Autowired private List<IPersonService> personServices; private Map<PersonType, IPersonService> personServiceMap; @PostConstruct public void init() { personServiceMap = new HashMap<>(); for (IPersonService personService : personServices) { personServiceMap.put(personService.supportedPersonType(), personService); } } public void delegate(PersonType mode) { personServiceMap.get(mode).run(); } } 

(Error handling omitted for simplicity).

+5
source

In my application, we solved a similar problem by placing services on a map. Consider a Map<PersonType,IPersonService> serviceMap , defined as a bean and injected into your class. Then follow the simple delegation method

 public void delegate(PersonType mode) { IPersonService service = serviceMap.get(mode); if (service!=null){ service.run(); }else{ //do something if service is null } } 
+1
source

You can store the bean service name (or class type) in an enumeration and extract beans from the application context using getBean by name (or by class type, respectively).

In addition, all services will need to implement an interface that has a startup method.

 interface ModeService { void run(); } enum PersonType { STUDENT("studentService"), PROF("profService"); private String serviceBean; public PersonType(String serviceBean) { this.serviceBean = serviceBean); } public String getServiceBean() { return serviceBean; } } 

in the delegate, you can use the following. ((ModeService)applicationContext.getBean(mode.getServiceBean()).run()

Thus, only the enumeration update should be updated with the type of service to be used, and no delegation method change is required.

0
source

All Articles