preface
I haven’t shared my work summary for a long time, but here is a code optimization summary. Using template method + strategy + factory method mode optimization code, patience points to read, should be helpful to everyone ~
This article has been contributed to Github
Github.com/whx123/Java…
Public number: a boy picking up snails
Before optimizing code
First, let’s take a look at similar business scenarios. In short, that is: multiple merchants access our system through a similar process through HTTP requests.
Before optimization, each company corresponds to a handle service, and the pseudocode is as follows:
CompanyAHandler implements RequestHandler {Resp hander(req){queryMerchantInfo(); / / the signature of the signature (s); HttpRequestbyProxy () // verify(); CompanyBHandler implements RequestHandler {Resp hander(Rreq){queryMerchantInfo(); / / the signature of the signature (s); // HTTP request (without proxy) httpRequestbyDirect(); / / attestation verify (); }} CompanyBHandler implements RequestHandler {Resp hander(Rreq){queryMerchantInfo(); // Call requestByWebservice(); }}Copy the code
Optimize code thinking
My way of thinking about optimizing code is if you have duplicate code, take it out first, or you have common variables, or you have common methods, and you have common classes. So there’s a common method for querying merchant information, adding signatures, and HTTP requests. This class is used to query the merchant information, add the HTTP request, and verify the request. This class is used to query the merchant information, add HTTP request, and verify the request
Template method pattern
In Template Pattern, an abstract class exposes a method/Template that executes its methods. Its subclasses can override method implementations as needed, but the calls will be made in the manner defined in the abstract class. This type of design pattern is behavioral.Copy the code
Since each Handler is a similar process, define an abstract class to query merchant information, add signatures, HTTP requests, check signatures and so on, just like a template. Then, what happens because some merchants use HTTP proxies and some don’t? Define an abstract method and give it to subclasses. If it can share it, put it in the parent class. If it can’t share it, put it in the subclass.
The abstract class AbstractCompanyCommonService implements ICompanyCommonService {/ / template method Resp handlerTempPlate (the req) { QueryMerchantInfo (); / / the signature of the signature (s); If (isRequestByProxy()){httpProxy(); }else{ httpDirect(); } // check the verifySinature(); Boolean isRequestByProxy(); }Copy the code
Subclass merchant A realizes:
CompanyAServiceImpl extends AbstractCompanyCommonService{ Resp hander(req){ return handlerTempPlate(req); } // company A is going to proxy Boolean isRequestByProxy(){return true; }Copy the code
Subclass merchant B implements:
CompanyBServiceImpl extends AbstractCompanyCommonService{ Resp hander(req){ return handlerTempPlate(req); } // company B is not going to go proxy Boolean isRequestByProxy(){return false; }Copy the code
The strategy pattern
Careful readers will notice, and even question, that your merchant C service implementation is not quite the same as the common template you define. Of course, in real development, it is too common not to define the template as you define. Requirements are the product, not according to your template, but the code serves the requirements. Well, without further ado, I used a strategic pattern to optimize this problem.
In the Strategy Pattern, the behavior of a class or its algorithm can be changed at run time. This type of design pattern is behavioral.Copy the code
Strategic patterns are abstract to understand, right? As I understand it, the strategy pattern is to define a method (called an algorithm) and give subclasses their own implementation. It essentially defines a method/interface and lets subclasses implement it themselves. Take a look at the code:
// Define a method and hand the policy to subclasses to implement. interface ICompanyCommonService{ Resp hander(req); }Copy the code
Merchants and merchants B or unchanged, in front of the use of abstract classes AbstractCompanyCommonService template, the template does not meet the merchants C, merchants can oneself to achieve, C each subclass to the behavior of the implementation, is the embodiment of the strategy pattern, as follows:
CompanyCServiceImpl extends AbstractCompanyCommonService {Res hander (the req) {/ / query merchants information queryMerchantInfo (); requestByWebservice(); } Boolean isRequestByProxy(){return false; }Copy the code
Factory method pattern
How will merchant A, B, C services be managed? Before, they were respectively given to A, B, C services to implement handler. Now, I don’t know how to manage, how will I know which to call? Don’t panic. The solution is the factory approach.
In factory mode, we create objects without exposing the creation logic to the client, and by using a common interface to point to the newly created objects.Copy the code
The factory method pattern is implemented in this way: the interface defines an enumeration, each service implementation reimplements the enumeration, sets the unique flag enumeration, and hands it over to the Spring container to manage. Look at the code:
interface ICompanyCommonService{ Resp hander(req); CompanyEnum getCompanyEnum(); } CompanyAServiceImpl extends AbstractCompanyCommonService{ Resp hander(req){ return handlerTempPlate(req); } // company A is going to proxy Boolean isRequestByProxy(){return true; } CompanyEnum getCompanyEnum(){ return CompanyEnum.A; } CompanyBServiceImpl extends AbstractCompanyCommonService{ Resp hander(req){ return handlerTempPlate(req); } // company B is not going to go proxy Boolean isRequestByProxy(){return false; } CompanyEnum getCompanyEnum(){ return CompanyEnum.B; }Copy the code
Here comes the factory method model:
@Component public class CompanyServiceFactory implements ApplicationContextAware { private static Map<CompanyEnum, ICompanyCommonService> map = new HashMap<>(); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map<String, ICompanyCommonService> tempMap = applicationContext.getBeansOfType(ICompanyCommonService.class); tempMap.values().forEach(iCompanyCommonService -> map.put(iCompanyCommonService.getCompanyEnum(), iCompanyCommonService)); } public Resp handler(req) { return map.get(CompanyEnum.getCompanyEnum(req.getCompanyFlag()).hander(req); }}Copy the code
The last suggestion
Finally, don’t just use a design pattern in order to use it. Use it when you find it works in your code. Here’s the final code:
@Service public class CompanyHandler implements RequestHandler { @Autowire private CompanyServiceFactory companyServiceFactory; Resp hander(req){ return companyServiceFactory.handler(req); }}Copy the code