Map + functional interface method to solve if else

Posted by Perry Mason on Fri, 21 Jan 2022 17:31:59 +0100

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

Implementation method:

  1. Determine which data table to query according to coupon type resourcetype - > resource type

  2. 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:

  1. 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.

  2. 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