Eliminate if-else/switch-case in code

Posted by mightymouse on Tue, 07 May 2019 07:35:04 +0200

In many cases, there will be many branches in our code, and the code below the branches has some complex logic, I believe that many people like to use if-else/switch-case to achieve. If you don't do well, you will put the implementation code directly under the branch of if-else/switch-case:

switch ( type ) {
    case case1:
        ...
        ...
        break;
    case case2:
        ...
        ...
        break;
    case case3:
        ...
        ...
        break
    default:
        return null;
}

 Such code is not only tedious, but also very difficult to read.Do a better job of encapsulating these logic functions and call them in branches:

switch ( type ) {
    case case1:
        return case1Func();
    case case2:
        return case2Func();
    case case3:
        return case3Func();
    default:
        return null;
}

 

Even this is a process-oriented way of thinking. I always like to write C programs in the past. There is no design pattern to speak of. Not only does it violate the open-close principle, but with the increase of switch-case branches, the code will become more and more verbose. In fact, this code has mature patterns to eliminate many if-else/switch-case branches. This article teaches you how to eliminate if-else/switch-case in Spring by annotation+strategy mode+simple factory. Let's take the personal center of QQ space as an example. If there are four tab s in the personal center of QQ space, they are my talk, my log, my photos and my visitors. The general background code is likely to be as follows:
//Enumeration of tab names:
public enum UserRelatedType {
    /**
     * say something
     */
    SHUOSHUO("say something"),

    /**
     * Journal
     */
    RIZHI("Journal"),

    /**
     * Release
     */
    ZHAOPIAN("Photo"),

    /**
     * Visitor
     */
    FANGKE("");

    private String desc;

    UserRelatedType(String desc) {
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

List the code of tab related to QQ user's personal center:

public List<UserRelatedVO> listRelated(UserRelatedQuery query){

    UserRelatedType relatedType = UserRelatedType.valueOf(StringUtils.upperCase(query.getType()) );
    switch ( relatedType ) {
        case SHUOSHUO:
            return listRelatedShuoshuo( query );
        case RIZHI:
            return listRelatedRizhi( query );
        case ZHAOPIAN:
            return listRelatedZhaopian( query );
        case FANGKE:
            return listRelatedFangke( query );
        default:
            return null;
    }
}

Using annotation + strategy mode + simple factory, the reconstructed code is as follows:

1. Define a comment to completely eliminate if-else:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RelatedTypeAnnotation {
    /**
     * User-related type names
     */
    UserRelatedType value();
}

2. First, an interface is defined, and all tabs need to implement the interface. list is the method of tab data display.

public interface UserRelated {

    /**
     * List details
     *
     * @param query
     * @return
     */
    List<UserRelatedVO> list(UserRelatedQuery query);
}

3. Define the implementation of specific tab s and inherit the UserRelated policy interface

What I said

@Component("userRelatedShuoshuo")
@RelatedTypeAnnotation( value = UserRelatedType.SHUOSHUO )
public class UserRelatedShuoshuo implements UserRelated {
    @Override
    public List<UserRelatedVO> list(UserRelatedQuery query) {
        System.out.println("I say!");
        return list;
    }
}

My diary

@Component("userRelatedRizhi")
@RelatedTypeAnnotation( value = UserRelatedType.RIZHI )
public class UserRelatedRizhi implements UserRelated {
    @Override
    public List<UserRelatedVO> list(UserRelatedQuery query) {
        System.out.println("My log!");
        return list;
    }
}

My photo

@Component("userRelatedZhaopian")
@RelatedTypeAnnotation( value = UserRelatedType.ZHAOPIAN )
public class UserRelatedZhaopian implements UserRelated {
    @Override
    public List<UserRelatedVO> list(UserRelatedQuery query) {
        System.out.println("My Photo!");
        return list;
    }
}

My visitor

@Component("userRelatedFangke")
@RelatedTypeAnnotation( value = UserRelatedType.FANGKE )
public class UserRelatedFangke implements UserRelated {
    @Override
    public List<UserRelatedVO> list(UserRelatedQuery query) {
        System.out.println("My visitor!");
        return list;
    }
}

3. Define a tool class for retrieving bean s from Spring context

@Component
public class SpringContextUtil implements ApplicationContextAware {

    private ApplicationContext context;

    public ApplicationContext getContext() {
        return context;
    }

    @Override
    public void setApplicationContext(ApplicationContext context)throws BeansException {
        this.context = context;
    }
}

4. Define a simple factory to produce various tab objects.

 

@Component
public class UserRelatedFactory {

    @Autowired
    SpringContextUtil springContextUtil;
    
    private static Map<UserRelatedType, UserRelated> userRelatedMap = Maps.newConcurrentMap();

    //Factory saves Spring assembly related beans with Map
    public UserRelatedFactory(){
        Map<String, Object> beanMap = springContextUtil.getContext().getBeansWithAnnotation(RelatedTypeAnnotation.class);

        for(Object userRelated : beanMap.values()) {
            RelatedTypeAnnotation annotation = userRelated.getClass().getAnnotation(RelatedTypeAnnotation.class);
            userRelatedMap.put(annotation.value(), (UserRelated)userRelated);
        }
    }

    public static UserRelated createRelated(UserRelatedType relatedType) {
        return userRelatedMap.get( relatedType );
    }
}

5. The code to be invoked (listRelated will be invoked in the controller).

public List<UserRelatedVO> listRelated(UserRelatedQuery query){

    UserRelatedType relatedType = UserRelatedType.valueOf(StringUtils.upperCase(query.getType()) );
    UserRelated related = UserRelatedFactory.createRelated( relatedType );
    if( related != null ) {
        return related.list( query );
    } else {
        return null;
    }
}

 

If you need to add a tab to the reconstructed code, such as my friend, you just need to add a new type to inherit UserRelated to implement the list and add the corresponding annotations.

 

Author: Waterhead Contamination
Link: https://juejin.im/post/5ca9f113e51d452b5e458ec3
Source: Nuggets

Topics: Java Spring