2015-04-04 26 views
8

我正在開發一個需要將服務添加到組件的項目。 Service類是沒有任何方法的接口。以下是我的服務如何工作的示例:泛型與「擴展」和「超級」的通配符

public interface Service { } 

public interface CarWash extends Service { 
    void washCar(Car car); 
} 

public interface CarRepair extends Service { 
    void repairCar(Car car); 
} 

現在這些服務有很多實現。單個類可以實現多個服務,因爲這車庫類:

public class Garage implements CarWash, CarRepair { 
    @Override 
    public void washCar(Car car) { /* .. */ } 
    @Override 
    public void repairCar(Car car) { /* .. */ } 
} 

當添加到組件服務,我不希望需要使用該服務的所有任務,但例如使用Garage僅洗車(CarWash)但不能修理(CarRepair)。因此我指定的任務類,就像這樣:

void addService(Service service, Class<? extends Service> task); 

要檢查服務是否可以真正執行的任務,我使用泛型:

<T extends Service> addService(T service, Class<? super T> task); 

這種運作良好,但不檢查提供的任務實際上是一個任務(實現Service類),所以這會工作:

addService(myTask, Object.class); 

我正在尋找一種方法符合規範IFY是service需要實現(延長)的tasktask是擴展Service接口,這樣(不編譯)

<T extends Service> addService(T service, Class<? super T extends Service> task); 
+1

如何:' void addService(S服務,類 clazz);'? – 2015-04-04 21:39:12

回答

7

我認爲<T extends Service, S extends T> void addService(S service, Class<T> clazz)聽起來符合您的條件:

public static class Foo {                     
    public interface Service { }                   

    public interface CarWash extends Service {                
    void washCar();                      
    }                          

    public interface CarRepair extends Service {               
    void repairCar();                     
    }                          

    static <T extends Service, S extends T> void addService(S service, Class<T> clazz) {}     

    public static void main(String[] args) {                
    addService(null, CarWash.class); // Fine.                 
    addService(null, Object.class); // Compilation error.               
    } 
} 

(I增加了一些靜力學和從方法簽名除去Car,因爲我沒有這些的定義來編譯)

+0

作品,非常感謝!我遇到的唯一問題是強制所有數組元素具有相同類型的可變參數,因此我無法編寫'addService(null,CarWash.class,CarRepair.class);'。 – Frithjof 2015-04-04 21:50:05

+0

那麼現在你沒有詢問可變參數......這聽起來像是你並不真正想要使用數組,而應該更喜歡使用Iterable, 'static void addService(S service,Iterable <?extends Class > clazzes)''。但我認爲這對於執行所有這些類的「服務」來說並不合適。我認爲在這種情況下,您實際上可以更好地定義帶有1,2,3等類參數的顯式過載。聽起來很亂。 – 2015-04-04 21:53:43

+0

我同意。我認爲把它作爲一個參數並且多次調用該方法來爲多個任務添加服務是很好的,就像你在答案中一樣。 – Frithjof 2015-04-04 21:58:58

1

這也可能是罰款,這取決於你如何使用的service類型:

<T extends Service> void addService(T service, Class<T> task) 

如果servicetask代表的類型的子類型,那麼它總是可以upcasted。

addService(new Garage(), CarWash.class); // OK, Garage is a CarWash 

我遇到的唯一問題是,強制所有數組元素是相同類型的可變參數,因此,我不能寫addService(null, CarWash.class, CarRepair.class);

這實際上是一個困難Java泛型的問題。 (C++可以通過variadic templates來實現,這是Java不太可能獲得的功能。)

因此,在Java中解決此問題的方法之一是運行時驗證,例如,:

<T extends Service> void addService(
     T service, Class<? super T> tasks...) { 
    for(Class<? super T> task : tasks) 
     if(!Service.class.isAssignableFrom(tasks)) 
      throw new IllegalArgumentException(); 
} 

(或者使用Class<? extends Service>,檢查task.isInstance(service)

但我知道,我們真的不喜歡這一點。 ; )

的Java確實有一些所謂的intersection type(其中,如果我們有一個類型<? extends T & U>,該T & U部分被稱爲交集型),但交集型不能結合superextends和他們另有相當的還有什麼限制他們可以做。