服务定位模式消除ifelse

2023-03-12

一、场景

服务类定义了一堆操作的抽象接口。具体的服务提供者实现这个接口。分离的服务定位器提供了通过查询获取服务方法,同时隐藏了服务提供者的具体细节和定位它的过程。

场景:根据文件类型,使用CSV解析器或者JSON解析器,在调用客户端的时候使用if else去做判断,例如:

if (type == 'CSV') {
	//.. CSV解析
} else if (type == 'JSON') {
	//.. JSON解析器处理
}

当我们新增一种类型时,就需要修改这里的代码去适配新的类型。

这种情况耦合程度太高。

此时我们可以使用服务定位模式去处理这种情况(原理是通过反射的方式,根据bean的name去获得对应的实现类,从而进行解析)

二、定义解析接口

/**
 * @Author: huanghwh
 * @Date: 2023/03/12 下午9:30
 * @Description: 解析器接口
 */
public interface Parser {


    /**
     * 解析
     *
     * @param reader reader
     * @return {@link List}
     */
    List parse(Reader reader);

}
/**
 * @Author: huanghwh
 * @Date: 2023/03/12 下午9:31
 * @Description: json解析器
 */
@Component("JSON")
@Log4j2
public class JsonParser implements Parser {


    @Override
    public List parse(Reader reader) {
        log.info("JSON解析器");
        return new ArrayList();
    }
}
/**
 * @Author: huanghwh
 * @Date: 2023/03/12 下午9:32
 * @Description: csv解析器
 */
@Component("CSV")
@Log4j2
public class CsvParser implements Parser {


    @Override
    public List parse(Reader reader) {
        log.info("CSV解析器");
        return new ArrayList();
    }
}

三、定义服务定位接口

根据类型获取解析器

/**
 * @Author: huanghwh
 * @Date: 2023/03/12 下午9:35
 * @Description: 服务定位模式,服务定位接口
 */
public interface ParseFactory {

    /**
     * 根据类型获取解析器
     *
     * @param contentType 类型
     * @return {@link Parser}
     */
    Parser getParser(ContentType contentType);

}

/**
 * @Author: huanghwh
 * @Date: 2023/03/12 下午9:39
 * @Description: 服务定位接口配置类
 */
@Configuration
public class ParserConfig {


    @Bean("parserFactory")
    public FactoryBean serviceLocatorFactoryBean() {
        ServiceLocatorFactoryBean serviceLocatorFactoryBean = new ServiceLocatorFactoryBean();
        // 设置服务定位接口
        serviceLocatorFactoryBean.setServiceLocatorInterface(ParseFactory.class);
        return serviceLocatorFactoryBean;
    }


}

四、使用demo

1、首先根据类型获取解析器

2、调用解析的解析方法

思考:如果直接使用反射,是否可以省去服务定位接口与配置类?

/**
 * @Author: huanghwh
 * @Date: 2023/03/12 下午9:42
 * @Description: 服务定位模式实现demo
 */
@RestController
@RequestMapping(("/locator"))
public class demo {

    @Autowired
    private ParseFactory parseFactory;


    @GetMapping("/getAll")
    public List getAll(ContentType contentType) {
        Reader reader = null;
        // 使用服务定位模式获取对应的解析器,执行解析
        Parser parser = parseFactory.getParser(contentType);
        List result = parser.parse(reader);
        return result;
    }


}