Recently, I wrote a service: query the distribution method grantType and collection rules according to the coupon type resourceType and code resourceId
Implementation method:
-
Determine which data table to query according to coupon type resourcetype - > resource type
-
According to the code resourceid - > go to the corresponding data table to query the distribution method, grantType and collection rules of coupons
There are many types of coupons, corresponding to different database tables:
-
Red envelope - red envelope distribution rule table
-
Shopping voucher - shopping voucher form
-
QQ member
-
Takeout member
The actual coupons are far more than these. This demand requires us to write a business distribution logic
The first thought you can think of is if else or switch case:
switch(resourceType){ case "Red envelopes": Query the distribution method of red envelopes break; case "Shopping voucher": Query the distribution method of shopping vouchers break; case "QQ member" : break; case "Takeout member" : break; ...... default : logger.info("The coupon type cannot be found resourceType And the corresponding distribution method"); break; }
If you want to write this, the code of a method is too long, affecting readability. (don't look at the above. There is only one sentence in the case, but there are many lines in the actual situation)
Moreover, the entire if else code has many lines, which is inconvenient to modify and has low maintainability.
Strategy mode
The policy mode is to extract the logic in the if statement and write it into a class. If you want to modify a logic, you can only modify the logic of a specific implementation class, and the maintainability will be good.
Strategy mode
"The policy pattern is still if else when business logic is assigned", but it is better maintained than if else in the first idea...
switch(resourceType){ case "Red envelopes": String grantType=new Context(new RedPaper()).ContextInterface(); break; case "Shopping voucher": String grantType=new Context(new Shopping()).ContextInterface(); break; ...... default : logger.info("The coupon type cannot be found resourceType And the corresponding distribution method"); break;
But the disadvantages are also obvious:
-
If there are many if else judgments, there will be many corresponding specific policy implementation classes. There are only two specific policy implementation classes above. The query red envelope distribution method is written in class RedPaper, and the Shopping voucher is written in another class Shopping; If there are multiple QQ members and takeout members of the resource type, don't you have to write two more categories? A little trouble
-
"Can't look down on the whole business logic of distribution"
Map + functional interface
lambda expressions, a new feature of Java 8, are used
-
Put the judgment conditions in the key
-
The corresponding business logic is placed in value
The advantage of this sub writing is very intuitive. You can directly see the "business logic corresponding to judgment conditions"
Demand: query the distribution method "grantType" according to the coupon (resource) type "resourceType" and code "resourceId"
Upper Code:
@Service public class QueryGrantTypeService { @Autowired private GrantTypeSerive grantTypeSerive; private Map<String, Function<String,String>> grantTypeMap=new HashMap<>(); /** * Initialize the business dispatch logic instead of the if else part * key: Coupon type * value: lambda Expression, and finally get the distribution method of the coupon */ @PostConstruct public void dispatcherInit(){ grantTypeMap.put("Red envelopes",resourceId->grantTypeSerive.redPaper(resourceId)); grantTypeMap.put("Shopping voucher",resourceId->grantTypeSerive.shopping(resourceId)); grantTypeMap.put("qq member",resourceId->grantTypeSerive.QQVip(resourceId)); } public String getResult(String resourceType){ //The Controller queries the grant type according to the coupon type resourceType and code resourceId Function<String,String> result=getGrantTypeMap.get(resourceType); if(result!=null){ //Pass in resourceId:: execute this expression to obtain grantType of String type return result.apply(resourceId); } return "The issuing method of the coupon cannot be queried"; } }
If there are many lines of business logic in a single if statement block, we can extract these business operations and write them into a separate Service, that is:
//Specific logical operation @Service public class GrantTypeSerive { public String redPaper(String resourceId){ //Distribution method of red envelopes return "Issued at 9:00 at the end of each week"; } public String shopping(String resourceId){ //Distribution method of shopping vouchers return "Issued at 9:00 every Wednesday"; } public String QQVip(String resourceId){ //Distribution method of qq members return "The second kill starts at 0:00 every Monday"; } }
The input parameter String resourceId is used to query the database. It is simplified here. It is not processed after passing the parameter.
Result of http call:
@RestController public class GrantTypeController { @Autowired private QueryGrantTypeService queryGrantTypeService; @PostMapping("/grantType") public String test(String resourceName){ return queryGrantTypeService.getResult(resourceName); } }
Result of http call
Using Map + functional interface also has disadvantages:
Your teammates have to know lambda expressions. He won't let him go by himself
Finally, let's review what this article says:
-
The policy mode is completed through interface, implementation class and logic dispatch. The logic of "if statement block" is extracted and written into "one class" for better maintenance.
-
Map + functional interface through map Get (key) instead of if else business dispatch can avoid the problem of increasing classes and difficult to overlook the whole business logic caused by the policy pattern.