This article comes from the author's contribution, the original author: God loves apples
At present, shell house hunting is my employer in Mordor. I usually focus on some java related technologies. I hope you can find something useful in this article. Personal level is limited. If there is any error in the article, please point it out and communicate with each other in the message area.
I think you've seen all kinds of explanations and sermons of "strategic models" more or less. This article is to "clarify" the strategic models and try to answer the following questions:
- How does the strategy pattern optimize the business logic code structure?
- How can I kill a chicken with a scalpel? Just a few if else scenarios I need to use strategy mode?!
- Is there any better code structure to implement the policy pattern?
How does the strategy pattern optimize the business logic code structure?
To answer this question, we must first skim the definition of strategic pattern and understand it from the definition
Textbook definition of strategic model
Its definition is simple: the behavior of a class or its algorithm can be changed at run time. Let's reduce it to code level. In human language, I will pass different "key s" to methods of this class to you at runtime, and your methods will execute different business logic. Take a closer look. Isn't that what if else does?
<img src="https://www.hollischuang.com/wp-content/uploads/2020/06/cat_gaitubao_240x240.jpg" alt="" width="240" height="240" />
What has the strategic model optimized?
In fact, the core idea of the strategy mode is the same as if else, which dynamically finds different business logic according to different key s. Is that all it is?
In fact, our strategy pattern is actually to adjust the code structure, using interface + implementation class + dispatch logic to make the code structure more maintainable.
<img src=" https://www.hollischuang.com/wp-content/uploads/2020/06/ Enterprise wechat 20200621044119. PNG "ALT =" "width =" 1136 "height =" 283 "class =" aligncenter size-full wp-image-5026 "/ >
Generally speaking, the textbook will end with the introduction of interface and implementation class, and other blogs will bring the reference to dispatch logic. There's no more verbosity here.
To sum up, the business logic that you should write should be written as usual when using the strategy 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 one implementation class, and replace it arbitrarily. It is better to maintain in complex scenarios (more business logic) than in direct if else.
How can I kill a chicken with a scalpel? Just a few if else scenarios I need to use strategy mode?!
I think my friends often have such dissatisfaction. My business logic is 34 lines. Do you give me a whole bunch of definitions? Is it necessary to be so troublesome? I think the specific business logic also needs to go to different classes. It's OK to be simple.
In fact, what we are dissatisfied with is the shortcomings of the strategic model:
1. The number of policy classes will increase. 2. Business logic will be distributed to each implementation class, and there is no place to look down on the whole business logic
In view of the shortcomings of the traditional strategy mode, we share an implementation idea here. This idea has helped our team to solve multiple complex if else business scenarios, which is relatively easy to understand. Java 8 features are needed in the code - implemented by using Map and functional interface.
show code structure directly: to demonstrate a simple idea, the code uses String type to simulate a business BO
Among them: 1. getCheckResult() is a traditional method; 2. getCheckResultSuper() defines the mapping relationship between "judgment condition" and "business logic" in the Map in advance. For details, please refer to the code notes
<pre>/**
- A business service class
*/
@Service
public class BizService {
/** * Traditional if else solution * When each business logic has 34 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 logic1"; } else if ("Verification 2".equals(order)) { return "Execute business logics 2"; }else if ("Verification 3".equals(order)) { return "Execute business logic 3"; }else if ("Verification 4".equals(order)) { return "Execute business logics 4"; }else if ("Verification 5".equals(order)) { return "Execute business logic5"; }else if ("Verification 6".equals(order)) { return "Execute business logics 6"; }else if ("Verification 7".equals(order)) { return "Execute business logics 7"; }else if ("Verification 8".equals(order)) { return "Execute business logics 8"; }else if ("Verification 9".equals(order)) { return "Execute business logic 9"; } return "Business error not returned in processed logic"; } /** * Business logic dispatch Map * Function Function & lt; String, String & gt; 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 logic1", order)); checkResultDispatcher.put("Verification 2", order -> String.format("Yes%s Execute business logics 2", order)); checkResultDispatcher.put("Verification 3", order -> String.format("Yes%s Execute business logic 3", order)); checkResultDispatcher.put("Verification 4", order -> String.format("Yes%s Execute business logics 4", order)); checkResultDispatcher.put("Verification 5", order -> String.format("Yes%s Execute business logic5", order)); checkResultDispatcher.put("Verification 6", order -> String.format("Yes%s Execute business logics 6", order)); checkResultDispatcher.put("Verification 7", order -> String.format("Yes%s Execute business logics 7", order)); checkResultDispatcher.put("Verification 8", order -> String.format("Yes%s Execute business logics 8", order)); checkResultDispatcher.put("Verification 9", order -> String.format("Yes%s Execute business logic 9", order)); } public String getCheckResultSuper(String order) { //Get the business logic code from the logical dispatch Dispatcher. 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 error not returned in processed logic"; }
}
</pre>
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); } }
<img src=" https://www.hollischuang.com/wp-content/uploads/2020/06/ Enterprise wechat 20200621034125. PNG "ALT =" "width =" 772 "height =" 341 "class =" aligncenter size-full wp-image-5025 "/ >
This is a simple demo, after which we will give some complex scene cases.
Lu Xun once said, "every time we solve a problem, there will be more problems.". Let's take a look at the benefits and problems of such an implementation.
<img src="https://www.hollischuang.com/wp-content/uploads/2020/06/20171127745604_tqerMF.jpg" alt="" width="444" height="274" />
The benefits are intuitive:
- Intuitively see the mapping relationship between "judgment condition" and business logic in a piece of code
- You don't need to define interfaces and implementation classes separately, but use existing functional interfaces directly (what? Don't know the functional interface? And the implementation class is the business code itself.
Bad points: 1. Need team members to know something about lambda expressions (what? Java 14 has come out. Are there any partners who use the new features of Java 8? )
Next, I will give a few 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 of my friends will say that my judgment conditions are multiple and complex. For example, you only have a single judgment logic. What should I do if I have multiple judgment logic?
Good solution: write a method of judging logic, and the key of Map is calculated by the method
<pre>/**
- 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 logic1", order)); checkResultDispatcherMuti.put("key_Order 1_Order 2", order -> String.format("Yes%s Execute business logics 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 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 error not returned in processing 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(); }
}
</pre>
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); } }
<img src=" https://www.hollischuang.com/wp-content/uploads/2020/06/ Enterprise wechat 2020062104141. PNG "ALT =" "width =" 881 "height =" 376 "class =" aligncenter size-full wp-image-5023 "/ >
Just design your key generation rules.
There are many lines in my business logic. Won't it be long to write directly in the Map of 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:
<pre>/**
- 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"; }
}
</pre>
<pre>/**
- 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 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 error not returned in 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(); }
}
</pre>
Call result:
<img src=" https://www.hollischuang.com/wp-content/uploads/2020/06/ Enterprise wechat 20200621051130. PNG "ALT =" "width =" 883 "height =" 361 "class =" aligncenter size full wp-image-5022 "/ >
summary
Finally, we try to answer the following questions: 1. How does the strategy pattern optimize the business logic code structure?
Abstract out the interface, encapsulate the business logic into one implementation class, and replace it arbitrarily. It is better to maintain in complex scenarios (more business logic) than in direct if else.
- How can I kill a chicken with a scalpel? Just a few if else scenarios I need to use strategy mode?!
What we are dissatisfied with is actually the shortcomings of traditional interface implementation: 1. There will be many policy classes. 2. The business logic is distributed in various implementation classes, and there is no place to look at the whole business logic
- Is there any better code structure to implement the policy pattern?
In view of the shortcomings of the traditional strategy mode, the idea of using Map and functional interface is shared.