【问题标题】:most suitable design pattern to choose parser based on input file最适合根据输入文件选择解析器的设计模式
【发布时间】:2017-07-31 04:28:05
【问题描述】:

我有所有 XML/JSON/CSV/EXCEL 格式的输入文件。

我已经为所有人编写了单独的解析器。 但我想在运行时选择我的解析。

哪种设计模式最合适?

我已经实现了诸如

if(file.endsWith(".csv"))
return CSVParser();
if(file.endsWith(".json"))
return JSONParser();
if(file.endsWith(".xml"))
return XMLParser();
else
return EXCELParser();

请提供建议/指南。

【问题讨论】:

  • 您可能想先提取扩展名,即最后一个句点之后的文本,将其转换为小写,然后使用字符串switch 语句,但除此之外,我觉得还可以。跨度>

标签: java design-patterns


【解决方案1】:

Simple factory 可以解决您的问题。它不是真正的 设计模式(不在最初的GoF 模式集中),而是一种编写解决方案的方法(又名idiom)。它与工厂方法和抽象工厂不同(请参阅上面的链接以了解区别)。

您不必使用静态方法。但是把它放在超类中是很实用的。

【讨论】:

    【解决方案2】:

    首先,所有解析器都实现相同的接口:

    public class CSVParser implements Parser {}
    public class JSONParser implements Parser {}
    public class XMLParser implements Parser {}
    public class EXCELParser implements Parser {}
    

    那么两种方案供参考:

    1.get parser in a method:

    public Parser getParser(String file){
        if(file.endsWith(".csv"))
            return CSVParser();
        if(file.endsWith(".json"))
            return JSONParser();
        if(file.endsWith(".xml"))
            return XMLParser();
        else
            return EXCELParser();
    }
    

    2。使用enum:

    public class ParserEnum {
        CSVParser("csv", new CSVParser()),
        JSONParser("json", new JSONParser()),
        XMLParser("xml", new XMLParser()),
        EXCELParser("excel", new EXCELParser);
    
        private String type;
        private Parser parser;
    
        ParserEnum(String type, Parser parser) {
            this.type = type;
            this.parser = parser;
        }
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public Parser getParser() {
            return parser;
        }
    
        public void setParser(Parser parser) {
            this.parser = parser;
        }
    }
    

    然后从枚举类型中获取解析器:

    public Parser getParser(String file){
        if(file.endsWith(".csv"))
            return ParserEnum.CSVParser.getParser;
        // ...
    }
    

    【讨论】:

    • 您为什么认为解析器还没有实现通用接口?问题代码有四个return new XxxParser() 语句,因此除非返回类型为Object,否则它将是接口或公共基类。您的回答没有增加任何价值,因为枚举仍然需要完全相同类型的多个 if 语句。
    【解决方案3】:

    您可以使用工厂设计模式..让子类根据输入决定要实例化哪种类型的解析器..解析器的客户端也不必知道通过声明一个通用接口或抽象类来实例化哪种类型的解析器。 .对于客户来说,它就像

    一样简单

    Parser parser=ParserFactory.getParser(String file);

    parser.parse(file);

    【讨论】:

    • “让子类决定”意味着工厂方法,但该模式需要多态调用(并且getParser 不是多态的)。您使用的是 simple factory with a static method,这是一种不同的模式。
    • @Fuhrmanator 我的意思是一样的..在简单工厂或工厂方法之间选择的灵活性取决于用户我相信..感谢您的反对:)
    【解决方案4】:

    由于解析器的数量是有限的并且接受相同的初始化参数,原型模式将最适合如下。注意:Prototype 使用克隆,不会每次都创建新对象。我相信我们需要非共享实例。

    public class ParserRepository {
        private Map<String,BaseParser> prototypes = new HashMap<>();
        public ParserRepository(){
            prototypes.put(".csv",new CSVParser());
            prototypes.put(".json",new JSONParser());
            prototypes.put(".xml",new XMLParser());
        }
    
        public BaseParser getParser(String extension) {
            BaseParser parser = null;;
            try {
                parser = (BaseParser) prototypes.get(extension).clone();
            } catch (CloneNotSupportedException e) {
                // Handle exception here
                e.printStackTrace();
            }
            return parser;
        }
    }
    

    如果需要将新原型动态添加到存储库,可以为 ParserRepository 类公开适当的方法。

    【讨论】:

    • 原型的复杂性正在抵消“避免以标准方式(例如,使用'new'关键字)创建新对象的固有成本的问题,因为它对于给定的应用程序来说过于昂贵。”似乎部分模式不适用于 OP 的帖子。
    猜你喜欢
    • 1970-01-01
    • 2010-09-10
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多