For a project, we have a Controller/Service/DAO architecture. We implement calls to different providers' APIs so we ended up with some boilerplate code like this in every controller class:
enum {
PARTNER_A, PARTNER_B, PARTNER_C
}
public class MyController {
@Resource PartnerASearchService partnerASearchService;
@Resource PartnerBSearchService partnerBSearchService;
@Resource PartnerCSearchService partnerCSearchService;
public search(InputForm form) {
switch(form.getPartnerName()) {
case PARTNER_A: partnerASearchService.search();
break;
case PARTNER_B: partnerBSearchService.search();
break;
case PARTNER_C: partnerCSearchService.search();
break;
}
}
public otherMethod(InputForm form) {
switch(form.getProvider()) {
case PARTNER_A: partnerAOtherService.otherMethod();
break;
case PARTNER_B: partnerBOtherService.otherMethod();
break;
case PARTNER_C: partnerCOtherService.otherMethod();
break;
}
}
}
Which design pattern can I use to get rid of this switch in every controller? I would prefer the code to be something like the below:
public class MyController {
@Resource ServiceStrategy serviceStrategy;
public search(InputForm form){
serviceStrategy.search(form.getPartnerName())
// or
serviceStrategy.invoke(SEARCH, form.getPartnerName())
}
public otherMethod(InputForm form){
serviceStrategy.other(form.getPartnerName())
// or
serviceStrategy.invoke(OTHER, form.getPartnerName())
}
}
letting the serviceStrategy decide which service implementation to be called, and thus having the partner's switch in a single place.
I've used the term "strategy" because I've been told this design pattern could make it, but I'm not sure of the best way to use it or if there is a better approach to solve this problem.
EDIT: I've updated the question as the term provider is misleading. What I have in the input form is the name of the partner for which we do the request. I want a pattern that decides which is the correct implementation (which one of the several services) to use based on the partner's name in the form
Chain of responsibility pattern is used to achieve loose coupling in software design where a request from the client is passed to a chain of objects to process them.
In the release of the 8th version of PHP, the match() function is introduced which is the new alternative of switch-case. It is a powerful feature that is often the best decision to use instead of a switch-case.
If a problem has two solutions, one that fits in ten lines of code, and another one with hundreds of lines of code along with a pattern, please consider not using the pattern. Their presence isn't a quality measurement.
One of the most popular design patterns used by software developers is a factory method. It is a creational pattern that helps create an object without the user getting exposed to creational logic. The only problem with a factory method is it relies on the concrete component.
Generally, the form shouldn't need any knowledge of what "provider" is going to handle it. Instead, the providers should be able to explain which kinds of inputs they can handle.
I recommend using a form of Chain of Responsibility (incorporating the refactoring Replace Conditional with Polymorphism) that looks something like this (Groovy for simplicity):
interface ProviderService {
boolean accepts(InputForm form)
void invoke(String foo, InputForm form)
void other(InputForm form)
}
Each implementation of ProviderService
implements accepts
to indicate whether it can handle a particular form, and your controller stores a List<ProviderService> services
instead of individual references. Then, when you need to process a form, you can use:
ProviderService service = services.find { it.accepts(form) }
// error handling if no service found
service.other(form)
See the Spring conversion service for a comprehensive example of this pattern that's used in a major framework.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With