2017-09-14 82 views
-2

我有一个接口方法parse(String value),它可能有不同的实现,返回的地图<String, Integer><String, String>或任何东西。我怎样才能使这个通用性足以让我扩展为不同的返回类型?通用返回类型的接口方法

目前,我做的:

public interface Parser <K,V> { 

    Map<K,V> parse(String document); 
} 

但是,这将使它通用单独的地图。有人可以告诉我有没有办法让它适用于不同的返回类型?

+1

'分析器'也许? –

+1

像'public interface Parser {E parse(String document); }'? – 4castle

+0

@ 4castle我是新来的接口,可以向我解释它是如何工作的(你在这里提到的那个) – user3407267

回答

0

如果你希望它返回任何类型,只需用一个泛型类型定义它像T:

public interface Parser <T> { 

    <T> parse(String document); 
} 

这是可能的,但我怕你以后会遇到一个新的挑战。 Java的目前有现在的方式来实例化不同于一般类型的类,所以你也必须通过对该类类型作为参数:

public interface Parser <T> { 

    <T> parse(Class<T> clazz, String document); 
} 

你可以做到这一点,但我觉得应该进一步的设计,你的架构。如果文档中的返回类型可以是任何东西,那么在大多数情况下,这是一种设计较弱的气味,并且会导致意大利面代码。

+1

“'地图 ...'” - >这不会编译。 ['Map'](https://docs.oracle.com/javase/8/docs/api/java/util/Map.html)有两个通用参数。 – Turing85

+0

感谢您的注意。我纠正了例子。 –

1

如果你想让你的接口在返回类型中是通用的,我会建议扩展JoeC的评论。

自Java 8以来,有java.util.function-package,为基本转换提供接口。特别是,界面Function可以用于适合您的目的。我建议这样的实现:

// file: Parser.java 
import java.util.function.Function; 

public abstract class Parser<R> implements Function<String, R> { 

    @Override 
    public final R apply(String document) { 
     return (this.parse(document)); 
    } 

    abstract public R parse(String document); 
} 

对于上面的例子中的一个实例是这样的:

String document    = ...; 
Parser<Map<K, V>> mapParser = ...; // instantiate a fitting Parser 
Map<K, V> result   = mapParser.parse(document); 

(鉴于KV在这个代码块称为通用参数)。

你可以进一步指定的接口来获得较为简单的语法:

// file: MapParser.java 
import java.util.Map; 

public abstract class MapParser<K, V> extends Parser<Map<K, V>> {} 

有了这个(空)接口,您可以重新WIRTE上面的代码为:如前所述

String document   = ...; 
MapParser<K, V> mapParser = ...; // instantiate a fitting MapParser 
Map<K, V> result   = mapParser.parse(document); 

通过@matoni,可以编写接口IParserIMapParser并在其上设置抽象类别ParserMapParser

的接口提供了一种用于自一个class用户可以实现多个interface S比的灵活性,但只有extends一个其它class。然而,不利的是,接口IParserIMapParser的开发人员无法强制执行该方法apply(...)不能被覆盖。因此,理论上,Parser的实施者可以不同地实施apply(...)parse(...),这可能导致意外的行为。当使用抽象类ParserMapParser时,开发人员确实会强制执行apply(...)调用parse(...)并因此具有一致的行为。

+0

我删除了我的答案,因为它与你的一样 - 你更快:)。考虑用接口解析器替换抽象的解析器。 Java 8引入了'default'方法,它们与抽象类中的非抽象方法基本相同。 – matoni

+0

@matoni是Java 8的。但是对于一个抽象类,可以强制'apply(...)'在其他地方不会被覆盖并调用'parse(...)',从而保证了一致性行为。如果一个'Parser'的实例被用作流调用的一部分。 – Turing85

+0

当然,但在Java中,一切都是虚拟的,因此可以被重写。 Final关键字很少使用。使用接口更灵活,因为您可以实现多个接口,而使用抽象类可以只扩展一个父类。 – matoni

0

的意见已经给你一个很好的暗示,但我猜你需要的例子。

// imports elided 

interface Parser<T> { 

    T parse(String document); 

    Parser<Map<String, Integer>> static mapParser() { 
     // replace with actual parsing code 
     return document -> { 
      Map<String, Integer> result = new Hashmap<>(); 
      result.put(document, document.length()); 
      return result; 
     } 

    Parser<List<String>> static listParser() { 
     return document -> Collections.singletonList(document); 
    } 
} 

请注意,实现只是占位符 - 它们只是为了说明您可以创建的解析器类型。我还使用了一个更简洁的lambda表达式,因为您的接口只有一个实例方法parse(String document),它将其定义为FunctionalInterface,允许您在实现指定的接口方法时替换匿名lambda表达式。

调用者可以调用通过:

String document = "abc"; 
Map<String, Integer> lookup = Parser.mapParser().parse(document); 
List<String> list = Parser.listParser().parse(document); 
相关问题