美文网首页spring
Spring项目中用了这种模式,经理对我刮目相看

Spring项目中用了这种模式,经理对我刮目相看

作者: Raral | 来源:发表于2023-01-30 15:27 被阅读0次

    类似 工厂 + 策略

    前言

    不知道大家在项目中有没有遇到过这样的场景,根据传入的类型,调用接口不同的实现类或者说服务,比如根据文件的类型使用 CSV解析器或者JSON解析器,在调用的客户端一般都是用if else去做判断,比如类型等于JSON,我就用JSON解析器,那如果新加一个类型的解析器,是不是调用的客户端还要修改呢?这显然太耦合了,本文就介绍一种方法,服务定位模式Service Locator Pattern来解决,它帮助我们消除紧耦合实现及其依赖性,并提出将服务与其具体类解耦。

    实现思路

    1. 定义工厂接口
    //定义解析工厂接口, 通过不同类型,获取不同的解析器
    public interface ParserFactory {
        Parser getParser(ContentType contentType);
    }
    
    
    1. 定义配置, 设置服务定位工厂,以ParserFactory
    
    //定义一个配置类,配置解析器工厂 服务定位接口
    @Configuration
    public class ParserConfig {
    
        @Bean("parserFactory")
        public FactoryBean serviceLocatorFactoryBean() {
            //1.使用spring自带的服务定位工厂
            ServiceLocatorFactoryBean serviceLocatorFactoryBean = new ServiceLocatorFactoryBean();
            //设置服务定位接口
            serviceLocatorFactoryBean.setServiceLocatorInterface(ParserConfig.class);
            return serviceLocatorFactoryBean;
    
        }
    }
    
    1. 枚举类
    public enum ContentType {
        JSON(TypeConstants.JSON_PARSER),
        CSV(TypeConstants.CSV_PARSER);
        private final String parserName;
        ContentType(String parserName) {
            this.parserName = parserName;
        }
    
        @Override
        public String toString() {
            return this.parserName;
        }
    
        public interface TypeConstants {
            String CSV_PARSER = "csvParser";
            String JSON_PARSER = "jsonParser";
            String XML_PARSER = "xmlParser";
        }
    }
    
    
    1. 不同解析器实现
    public interface Parser {
        List parse(Reader r);
    }
    @Component(ContentType.TypeConstants.CSV_PARSER)
    public class CSVParser implements Parser{
        @Override
        public List parse(Reader r) {
            System.out.println("CSVParser.parse");
            return null;
        }
    }
    @Component(ContentType.TypeConstants.CSV_PARSER)
    public class JSONParser implements Parser{
        @Override
        public List parse(Reader r) {
            System.out.println("JSONParser.parse");
            return null;
        }
    }
    
    
    1. 客户端调用
    @Service
    public class Client2 {
    
        private ParserFactory parserFactory;
    
        @Autowired
        public Client2(ParserFactory parserFactory) {
            this.parserFactory = parserFactory;
        }
    
        public List getAll(ContentType contentType) {
            Reader reader = new Reader() {
                @Override
                public int read(char[] cbuf, int off, int len) throws IOException {
                    return 0;
                }
    
                @Override
                public void close() throws IOException {
    
                }
            };
    
            return parserFactory.getParser(contentType).parse(reader);
        }
    
    
    }
    
    

    我们已经成功地实现了我们的目标。现在再加新的类型,我们只要扩展添加新的解析器就行,再也不用修改客户端了,满足开闭原则。
    1.实际开发过程中如果相同bean类型只有一个,不建议使用ServiceLocatorFactoryBean增加复杂性;
    2.如果对于不同输入需要调用不同实现类,而返回类型,数据结构等信息相同时,可以考虑使用ServiceLocatorFactoryBean;例如:数据库连接池时,根据不同数据库类型名称获取数据库信息
    https://mp.weixin.qq.com/s/huwL9OAcvAMGObmMf5dcgw

    相关文章

      网友评论

        本文标题:Spring项目中用了这种模式,经理对我刮目相看

        本文链接:https://www.haomeiwen.com/subject/msimhdtx.html