Still solving if else with strategy mode? Map + functional interface method is YYDS!

Posted by blakogre on Sat, 29 Jan 2022 20:21:36 +0100

This paper introduces the specific application of strategy mode and how Map + functional interface can "better" solve the problem of if else.

Article catalogue

  • demand
  • Strategy mode
  • Map + functional interface
  • Finally, what does this article say

demand

Recently, I wrote a service: query the distribution method grantType and collection rules according to the coupon type resourceType and code resourceId

Implementation method:
  • According to the coupon type, resourcetype - > determine which data table to query
  • 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, which correspond 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 way, the code of a method is too long, which affects the readability. (don't look at the above. There is only one sentence in the case, but the actual situation is that there are many lines)

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, which will be maintainable.

The following is the specific structure of the policy pattern

The policy pattern is still if else when the 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 in the resource type, don't you have to write two more categories? A little trouble
  • You can't look down on the business logic of the whole dispatch

Map + functional interface

lambda expressions, a new feature of Java 8, are used

  • Put judgment conditions in key
  • The corresponding business logic is placed in value

The advantage of this sub writing is very intuitive, and you can directly see the business logic corresponding to the 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);
    }
}

Using Map + functional interface also has disadvantages:

  • Your teammate has to know lambda expression. He won't let him go to Baidu by himself

Finally, what does this article say

The policy mode is completed through interface, implementation class and logic dispatch. The logic of if statement block is extracted and written into a 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.

Topics: Java