‘This is my 16th day of the challenge. For more details, see:More article challenges

Set up a Flag and write something every day and stick to it.

How to gracefully eliminate if-else in a project

There are many ways to eliminate if-else, and this article combines the use of ArgumentResolver in Spring with an elegant way to do so.

Let’s see how ArgumentResolver works first

public class UserArgumentResolver implements HandlerMethodArgumentResolver {
  private static final String TOKEN_KEY = "token";

  @Override
  public boolean supportsParameter(MethodParameter parameter) {
      return parameter.hasParameterAnnotation(LoginUser.class);
  }

  @Override
  public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
      // Obtain the userID through session
      String token = webRequest.getHeader(TOKEN_KEY);
      User user = null;
      // Get user JSON from redis
      // user = JSON.parse(redis.get(token),User.class);

      returnuser; }}Copy the code

Where the controller needs to inject parameters

@RequestMapping(value = "/doSth", method = RequestMethod.POST)
public String feed(@LoginUser User user) {
  System.out.println("userId: " + JSON.toJsonString(user));
  return "success";
}
Copy the code

Declare the annotation LoginUser

@Target(ElementType.TYPE,ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RestController {

 String value(a) default "";

}
Copy the code

Configuration class Addition

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

  @Override
  public void addArgumentResolvers (List<HandlerMethodArgumentResolver> resolvers) {
    resolvers.add(newUserArgumentResolver()); }}Copy the code

Multiple ArgumentResolvers can be configured in the WebConfiguration.

If – else

Bike, bus,subway,train,plan

if (bike) {
    
} else if (bus) {
    
} else if (subway) {
    
} else if (train) {
    
} else if (plan) {
    
}else{}Copy the code

Write different reslovers

Define a unified interface

public interface TrafficResolver {

    boolean support(String type);

    Object resolver(Object argument);
}
Copy the code

Define the implementation class BusTrafficResolver, everything else omitted

@Compoment
public class BusTrafficResolver implements TrafficResolver{

  @Override
  public boolean support (String type) {
    return "BUS".equals(type);
  }

  @Override
  public Object resolver (Object argument) {
    // doSth
    return "bus resolver"; }}Copy the code

Service classes that really eliminate if-else

New ArrayList<>() is required if there are no beans in the List.

@Service
public class TrafficService {

  // required = false
  @Autowired(required = false)
  List<TrafficResolver> trafficResolverList = new ArrayList<>();

  public Object traffic(String type,Object argument){
    System.out.printf("trafficResolverList "+trafficResolverList.size());
    TrafficResolver resolver = getFirstResolver(type);
    if(resolver! =null) {return resolver.resolver(argument);
    }

    return "traffic not find. type: "+type;
  }

  private TrafficResolver getFirstResolver(String type){
    TrafficResolver resolver = trafficResolverList.stream()
        .filter(item -> item.support(type))
        .findFirst()
        .orElse(null);
    returnresolver; }}Copy the code

In this way, the decoupling of if-else invocation class is accomplished and high extensibility is achieved. It follows the principle of close for modification and open for extension.

Eliminate if-else completions. of course, you can use annotations to determine whether or not the annotation type is supported.

The if-else works pretty well, but don’t overdesign it unless you’re thinking about extensibility.