In many cases, there will be many branches in our code, and the code below branches has some complicated logic, I believe that many people like to use if-else/switch-case to implement. A bad one would put the implementation code directly under the if-else/switch-case branch:

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

Such code is not only long, it is also very difficult to read. A better way to do this is to wrap the logic into functions and call them in branches:

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

Even this is process-oriented writing, and I used to like this when I was writing C programs. There was no design pattern at all. Not only does it violate the open and close principle, but the code only gets more verbose as the number of switch-case branches increases. In fact, this code has a mature pattern to eliminate a lot of if-else/switch-case branches. This article will show you how to eliminate if-else/switch-case in Spring using annotations + policy mode + simple factory. Let’s take the personal center of Qzone as an example. Suppose there are four tabs in the personal center of Qzone to list my comments, my journal, my photos and my visitors. The usual backend code is likely to look like this:

Public enum UserRelatedType {/** ** ** */ SHUOSHUO("Tell me about"), /** * log */ RIZHI("Log"), /** * release */"Photos"), /** * visitors */ FANGKE("");

    private String desc;

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

    public String getDesc() {
        return desc;
    }

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

List QQ user personal center related TAB code:

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:
            returnnull; }}Copy the code

With annotations + policy pattern + simple factory, the refactored code is as follows:

1, Define an annotation to completely eliminate if-else:

@target (elementtype.type) @Retention(retentionPolicy.runtime) public @Interface RelatedTypeAnnotation {/** * User associated TYPE name */ UserRelatedType value(); }Copy the code

2. Define an interface that all tabs should implement. Where list is the TAB data display method.

Public interface UserRelated {/** * list details ** @param query * @return
     */
    List<UserRelatedVO> list(UserRelatedQuery query);
}
Copy the code

3. Define the implementation of each TAB and inherit the UserRelated policy interface

  • I talk about
@Component("userRelatedShuoshuo")
@RelatedTypeAnnotation( value = UserRelatedType.SHUOSHUO )
public class UserRelatedShuoshuo implements UserRelated {
    @Override
    public List<UserRelatedVO> list(UserRelatedQuery query) {
        System.out.println("My word!);
        returnlist; }}Copy the code
  • My log
@Component("userRelatedRizhi")
@RelatedTypeAnnotation( value = UserRelatedType.RIZHI )
public class UserRelatedRizhi implements UserRelated {
    @Override
    public List<UserRelatedVO> list(UserRelatedQuery query) {
        System.out.println("My log!);
        returnlist; }}Copy the code
  • My photo
@Component("userRelatedZhaopian")
@RelatedTypeAnnotation( value = UserRelatedType.ZHAOPIAN )
public class UserRelatedZhaopian implements UserRelated {
    @Override
    public List<UserRelatedVO> list(UserRelatedQuery query) {
        System.out.println("My picture!);
        returnlist; }}Copy the code
  • My visitors
@Component("userRelatedFangke")
@RelatedTypeAnnotation( value = UserRelatedType.FANGKE )
public class UserRelatedFangke implements UserRelated {
    @Override
    public List<UserRelatedVO> list(UserRelatedQuery query) {
        System.out.println("My visitor!);
        returnlist; }}Copy the code

Define a utility class that gets beans from the 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; }}Copy the code

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(); @postconstruct public void init{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) {
        returnuserRelatedMap.get( relatedType ); }}Copy the code

5. The code to call (listRelated will be called 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 {
        returnnull; }}Copy the code

If the refactored code needs to add a new TAB, such as My Friends, it simply adds a new type that inherits the List from UserRelated and annotates it accordingly.

This is a general solution, and should be considered if you have more than three if-else/switch-case branches that are similar and verbose. The code produced in this mode is object-oriented, clear, and easily extensible. Why not try it? Remember to pay attention to the public account oh, recording a C++ programmer to Java learning road.