I think everyone must have read the explanations and sermons of various "strategic models" more or less. This article is to "clarify" the strategic models and try to answer the following questions:
1. How does the policy pattern optimize the business logic code structure?
2. How can you kill a chicken with an ox knife? Just a few if else scenarios, I need to use the policy mode?!
3. Is there any better code structure to implement the policy pattern?
How does the policy pattern optimize the business logic code structure?
To answer this question, we must first pick up the definition of the strategy pattern and understand it from the definition
Textbook definition of strategy pattern
Its definition is very concise: the behavior of a class or its algorithm can be changed at run time. Let's reduce it to the code level. In human words, I pass different "key s" to the methods of this class at runtime, and your methods will execute different business logic. Take a closer look. Isn't that what if else did?
What does the strategy model optimize?
In fact, the core idea of the strategy mode is the same as if else. It dynamically finds different business logic according to different key s. Is that all it is?
In fact, the policy pattern in our mouth is actually to adjust the code structure, using interface + implementation class + dispatch logic to make the code structure more maintainable.
Generally, the interface and implementation class are explained in the textbook, and the dispatch logic will be mentioned in other blogs. There's no more wordy here.
To sum up, the business logic you should write is written as usual when using the policy mode. When the logic is dispatched, it is still a disguised if else. Its optimization point is to abstract the interface, encapsulate the business logic into implementation classes one by one, and replace them arbitrarily. It is easier to maintain in complex scenarios (more business logic) than if else directly.
How can you kill a chicken with an ox knife? Just a few if else scenarios, I need to use the policy mode?!
I think my partners often have such dissatisfaction. My business logic is only 3 or 4 lines. Can you give me a whole lot of class definitions? Is it necessary to be so troublesome? I think the specific business logic needs to be in different classes. Can it be simpler.
In fact, what we are dissatisfied with is the shortcomings brought by the strategic model:
1. Policy classes will increase
2. The business logic is scattered into various implementation classes, and there is no place to look down on the whole business logic
In view of the shortcomings of the traditional strategy model, I share an implementation idea here. This idea has helped our team solve multiple complex if else business scenarios. It is easy to understand. Java 8 features need to be used in the code - implemented by Map and functional interface.
Direct show code structure: to simply demonstrate an idea, the code uses String type to simulate a business BO
Of which:
-
getCheckResult() is a traditional approach
-
getCheckResultSuper() defines the mapping relationship between "judgment condition" and "business logic" in the Map in advance. Please refer to the code Notes for details
/** * A business service class */ @Service public class BizService { /** * Traditional if else solution * When each business logic has 3 or 4 lines, it is not worth using the traditional strategy mode, and the direct if else is not easy to read */ public String getCheckResult(String order) { if ("Check 1".equals(order)) { return "Execute business logic 1"; } else if ("Check 2".equals(order)) { return "Execute business logic 2"; }else if ("Check 3".equals(order)) { return "Execute business logic 3"; }else if ("Check 4".equals(order)) { return "Execute business logic 4"; }else if ("Check 5".equals(order)) { return "Execute business logic 5"; }else if ("Check 6".equals(order)) { return "Execute business logic 6"; }else if ("Check 7".equals(order)) { return "Execute business logic 7"; }else if ("Check 8".equals(order)) { return "Execute business logic 8"; }else if ("Check 9".equals(order)) { return "Execute business logic 9"; } return "Business errors are not returned in the processed logic"; } /** * Business logic assignment Map * Function It is a functional interface. Function < String, String > in the following code means to receive a Stirng type variable and return a String type result */ private Map<String, Function<String, String>> checkResultDispatcher = new HashMap<>(); /** * Initialize the business logic dispatch Map, where value stores the lambda expression */ @PostConstruct public void checkResultDispatcherInit() { checkResultDispatcher.put("Check 1", order -> String.format("yes%s Execute business logic 1", order)); checkResultDispatcher.put("Check 2", order -> String.format("yes%s Execute business logic 2", order)); checkResultDispatcher.put("Check 3", order -> String.format("yes%s Execute business logic 3", order)); checkResultDispatcher.put("Check 4", order -> String.format("yes%s Execute business logic 4", order)); checkResultDispatcher.put("Check 5", order -> String.format("yes%s Execute business logic 5", order)); checkResultDispatcher.put("Check 6", order -> String.format("yes%s Execute business logic 6", order)); checkResultDispatcher.put("Check 7", order -> String.format("yes%s Execute business logic 7", order)); checkResultDispatcher.put("Check 8", order -> String.format("yes%s Execute business logic 8", order)); checkResultDispatcher.put("Check 9", order -> String.format("yes%s Execute business logic 9", order)); } public String getCheckResultSuper(String order) { //Obtain the business logic code from the logical dispatch Dispatcher, and the result variable is a lambda expression Function<String, String> result = checkResultDispatcher.get(order); if (result != null) { //Execute this expression to get the result of String type return result.apply(order); } return "Business errors are not returned in the processed logic"; } }
Call http to see the effect:
/** * Simulate an http call */ @RestController public class BizController { @Autowired private BizService bizService; @PostMapping("/v1/biz/testSuper") public String test2(String order) { return bizService.getCheckResultSuper(order); } }
This is a simple demo demonstration, and then some complex scenario cases will be given.
Lu Xun once said, "every time a problem is solved, more problems will arise.". Let's take a look at the benefits and problems of this implementation.
The benefits are intuitive:
- In a piece of code, you can intuitively see the mapping relationship between "judgment condition" and business logic
- There is no need to define the interface and implementation class separately, and the existing functional interface (what? Do not know the functional interface? Go to find out), and the implementation class is directly the business code itself.
Bad points:
- Team members need to know something about lambda expressions (what? Java 14 is out, and are there any partners who use the new features of Java 8?)
Next, I'll give some if else scenarios that I often encounter in business, and use Map + functional interface to solve it
Solutions to problems in real business scenarios
Some friends will say that my judgment conditions are multiple and complex. For example, you have only a single judgment logic, but what should I do if I have multiple judgment logics?
Good solution: write a method for judging logic, and the key of Map is calculated by the method
/** * A business service class */ @Service public class BizService { private Map<String, Function<String, String>> checkResultDispatcherMuti = new HashMap<>(); /** * Initialize the business logic dispatch Map, where value stores the lambda expression */ @PostConstruct public void checkResultDispatcherMuitInit() { checkResultDispatcherMuti.put("key_Order 1", order -> String.format("yes%s Execute business logic 1", order)); checkResultDispatcherMuti.put("key_Order 1_Order 2", order -> String.format("yes%s Execute business logic 2", order)); checkResultDispatcherMuti.put("key_Order 1_Order 2_Order 3", order -> String.format("yes%s Execute business logic 3", order)); } public String getCheckResultMuti(String order, int level) { //Write a logic to generate a key: String ley = getDispatcherKey(order, level); Function<String, String> result = checkResultDispatcherMuti.get(ley); if (result != null) { //Execute this expression to get the result of String type return result.apply(order); } return "Business errors are not returned in the processed logic"; } /** * Judgment condition method */ private String getDispatcherKey(String order, int level) { StringBuilder key = new StringBuilder("key"); for (int i = 1; i <= level; i++) { key.append("_" + order + i); } return key.toString(); } }
Use http to simulate:
/** * Simulate an http call */ @RestController public class BizController { @Autowired private BizService bizService; @PostMapping("/v1/biz/testMuti") public String test1(String order, Integer level) { return bizService.getCheckResultMuti(order, level); } }
Just design the generation rules of your key.
Other partners will ask: my business logic has many lines. Won't it be very long to write directly in the Map of the checkResultDispatcherMuitInit() method?
Direct writing is of course long. We can abstract a service service to set business logic, and then call it in the definition.
Provide a business logic unit:
/** * Provide business logic unit */ @Service public class BizUnitService { public String bizOne(String order) { return order + "Various fancy operations 1"; } public String bizTwo(String order) { return order + "Various fancy operations 2"; } public String bizThree(String order) { return order + "Various fancy operations 3"; } }
/** * A business service class */ @Service public class BizService { @Autowired private BizUnitService bizUnitService; private Map<String, Function<String, String>> checkResultDispatcherComX = new HashMap<>(); /** * Initialize the business logic dispatch Map, where value stores the lambda expression */ @PostConstruct public void checkResultDispatcherComXInit() { checkResultDispatcherComX.put("key_Order 1", order -> bizUnitService.bizOne(order)); checkResultDispatcherComX.put("key_Order 1_Order 2", order -> bizUnitService.bizTwo(order)); checkResultDispatcherComX.put("key_Order 1_Order 2_Order 3", order -> bizUnitService.bizThree(order)); } public String getCheckResultComX(String order, int level) { //Write a logic to generate a key: String ley = getDispatcherComXKey(order, level); Function<String, String> result = checkResultDispatcherComX.get(ley); if (result != null) { //Execute this expression to get the result of String type return result.apply(order); } return "Business errors are not returned in the processed logic"; } /** * Judgment condition method */ private String getDispatcherComXKey(String order, int level) { StringBuilder key = new StringBuilder("key"); for (int i = 1; i <= level; i++) { key.append("_" + order + i); } return key.toString(); } }
Call result:
summary
Finally, let's try to answer the following questions:
1. How does the policy pattern optimize the business logic code structure?
The interface is abstracted, and the business logic is encapsulated into implementation classes one by one, which can be replaced arbitrarily. It is easier to maintain in complex scenarios (more business logic) than if else directly.
2. How can you kill a chicken with an ox knife? Just a few if else scenarios, I need to use the policy mode?!
What we are dissatisfied with is actually the shortcomings of the traditional interface implementation: 1. There will be many policy classes. 2. The business logic is scattered into various implementation classes, and there is no place to browse the whole business logic
3. Is there any better code structure to implement the policy pattern?
Aiming at the shortcomings of traditional strategy mode, this paper shares the idea of using Map and functional interface to realize it.
last
The front-end side must ask about basic knowledge. If you roll over in the basic knowledge, even if you play the framework again 6, it won't help you to learn webpack, git and node better, because the other party won't give you any more opportunities to show. Don't miss your happy company because of the foundation. The front-end basic knowledge is miscellaneous and numerous. It is not ok to understand it. Some really need to remember. Of course, we are the front-end engineers of Niu x. it is not necessary to recite knowledge points like reciting English words every day. As long as we pay more attention to summary in our daily work and brush down the questions at the front of the interview.
what? Don't you think it's right in front of you when you ask where the information is
And there is no place to view the whole business logic
3. Is there any better code structure to implement the policy pattern?
Aiming at the shortcomings of traditional strategy mode, this paper shares the idea of using Map and functional interface to realize it.
last
The front-end side must ask about basic knowledge. If you roll over in the basic knowledge, even if you play the framework again 6, it won't help you to learn webpack, git and node better, because the other party won't give you any more opportunities to show. Don't miss your happy company because of the foundation. The front-end basic knowledge is miscellaneous and numerous. It is not ok to understand it. Some really need to remember. Of course, we are the front-end engineers of Niu x. it is not necessary to recite knowledge points like reciting English words every day. As long as we pay more attention to summary in our daily work and brush down the questions at the front of the interview.
what? Don't you think it's right in front of you when you ask where the information is