【问题标题】:Extend an interface or aggregate interfaces扩展接口或聚合接口
【发布时间】:2015-08-10 15:39:01
【问题描述】:

我进退两难了。我有一个接口 Parser 和实现它的类将解析具体的文件格式。例如 - CSVParser 将解析 CSV 文件,XMLParser 将解析 XML 文件等等。

因此,接口 Parser 将是:

public interface Parser{

    public SomeObject parseFile(String pathToFile);

}

另一方面,一些解析器会有额外的参数,例如,一个告诉他们在文件中跳过哪些行的数组。现在这让我很困惑,我是否应该扩展 Parser 并添加方法,例如:

public interface BetterParser extends Parser{
    public SomeObject parseFileConsideringParameter(String pathToFile, int[] whichLinesToSkip)
} 

或者我应该聚合它们以便我的班级需要同时实现这两者:

public class concreteParser implements Parser, BetterParser{
}

我想在管道中有解析器不可知的部分,你会说:

Parser parser = ParserFactory.giveMeParser(type);
SomeObject so = parser.parseFile(path);

问题是,在某些情况下,我不会有告诉我要跳过哪些行的参数。

我知道我只能创建一个带有两个参数的方法,所以一些实现会传递另一个参数,而其他实现会传递 null,但这看起来很难看。

我真的很想避免局限于具体的实现,但是我该如何克服这个问题呢?也许我错过了什么?

【问题讨论】:

  • 是否依赖于跳行格式?是特定于特定解析器的东西,还是无论格式如何都需要做的事情?
  • 感谢您的关注。是的,它取决于格式。有些文件不需要,但有些文件需要。
  • 那么它应该是具体解析器的一部分,即不是接口的一部分。当您实例化解析器或让解析器以某种方式“检测”这些东西时,让它成为一个参数。在最坏的情况下,您可能会在解析器中注入一个“服务”,可以像 svc.GetCSVLinesToSkip() 一样调用它

标签: oop design-patterns


【解决方案1】:

这些接口的原因本质上是为了让服务提供者可以将接口绑定到它的实现。如果所述实现具有“变体”,那么允许这种变体的一种方法是实现常规的SomeObject parseFile(String pathToFile) 方法,该方法调用parseFileConsideringParameter() 并带有默认的whichLinesToSkip 参数以传递。然后,如果您需要告诉要跳过哪些行,您将检查 Parser 是否是 instanceof BetterParser,然后将 Parser 转换为 BetterParser 并使用该方法(但如下所述,instanceof 很少是解决方案) .

话虽如此,您的问题分为两部分:

  1. 聚合或扩展
  2. 如何处理实现中的变化

对于 1,这真的是个人喜好。两者都可以,但是扩展可能会表明 BetterParser 一个解析器,而不是依靠实现来传达这一点,只需实现两者即可。

对于 2,我在上面提到过。但是,大多数人说如果你使用instanceofthere's probably a better way。为此,您可以考虑让服务提供者使用两种方法,一种用于获取常规解析器,另一种用于获取 SkippableParser(例如)。

【讨论】:

    【解决方案2】:

    另一方面,一些解析器会有额外的参数,例如,一个告诉他们在文件中跳过哪些行的数组。现在这让我很困惑,我是否应该扩展 Parser 并添加方法,比如

       public interface BetterParser extends Parser{
            public SomeObject parseFileConsideringParameter(String pathToFile,     int[] whichLinesToSkip)
        } 
    

    不,拜托,只是不要。

    您可以尝试使用Decorator Pattern 的方法。

    interface Parser {
        public List<Token> parse(String pathToFile);
    }
    
    abstract class ParserDecorator implements Parser {
        protected Parser realParser;
        protected ParserDecorator(Parser rp) {}
        // delegates most of the methods to real parser...
    }
    
    class LineFilterParserDecorator extends ParserDecorator {
        private int[] linesToSkip;
        public LineFilterParserDecorator(Parser rp, int[] linesToSkip) {
            super(rp);
            this.linesToSkip = linesToSkip;
        }
    
        @override
        public List<Token> parse(Strint path) {
            List<Token> l = this.realParser.parse(path);
            // remove the skipped lines from the list
            return l;
        }
    }
    
    // Usage:
    
    Parser myParser = new LineFilterParserDecorator(new CSVParser(...), new int{10, 20,30}); // will skip lines 10, 20 and 30
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-28
      相关资源
      最近更新 更多