2017-09-14 86 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); 
相關問題