2015-04-18 26 views
2

我有以下接口如何使鑽石運算符在Java中動態類型參數?

public interface Splitter<T, V> { 
    V[] split(T arg); 
} 

下面是我使用來獲得分離器實現工廠方法實現。

工廠方法實現

public static <T, V> Splitter<T, V> getSplitter(Class<T> key1, Class<V> key2) { 

    if (key1 == Company.class && key2 == Department.class) 
     return (Splitter<T, V>) new CompanySplitterImpl(); 

    // more cases 
} 

以下是我在客戶端調用

Splitter<Company, Department> split = getSplitter(Company.class, Department.class); 

我想避免與執行客戶端代碼緊密耦合該編譯罰款。有沒有辦法避免硬編碼類型參數,即避免在被調用端使用公司和部門(Splitter<Company, Department>)並使用某些變量?有沒有一種方法可以通過它們從一些外部屬性文件加載?

僅供參考:我不確定它在Java中的可行性嗎?

+2

你在說什麼硬編碼類型參數?你想使用什麼變量? –

+0

我不知道你在問什麼。請提供您想要的代碼。 –

+0

@RohitJain編輯問題 – Vinit89

回答

1

你可以做的一件事是讓你的工廠不知道具體實現的任何內容,而是自己註冊它(或包含預定義列表),並詢問每個實現是否可以處理類型。例如,給定一個預定義列表像你上面的例子:

public class SplitterFactory { 
    private Set<Splitter> splitters = new HashSet<>() {{ 
     add(new CompanySplitterImpl()); 
    }}; 

    public static <T, V> Splitter<T, V> getSplitter(Class<T> key1, Class<V> key2) 
    { 
     for (Splitter splitter : splitters) { 
      if (splitter.canAccept(key1, key2)) { 
       return splitter; 
     }  
     // no matched splitter 
    } 
} 

顯然,這是一個很天真的解決方案,你可以更有效地執行查詢。如果你在編譯時不知道你的類型,你也可以在工廠有一個註冊機制來在運行時包含新的類型。因爲Splitter現在負責報告它可以處理的類型,它可以完全擴展。

+1

你的'splitters'集合是使用原始'Splitter'定義的。不建議。 – RealSkeptic

0

不是一個好辦法,但辦法之一是:

String companyClass = "Company"; 
String departmentClass = "Department"; 
Splitter split = getSplitter(Class.forName(companyClass), Class.forName(departmentClass));//raw splitter 
System.out.println(split.split(new Company()));//you could use reflection here to create instance from companyClass String. 
+1

如何使用原始類型是件好事? – RealSkeptic

1

你可以做一個簡單的地圖類,您可以列出它們備份到:

public final class SplitterMap { 

    private final List<SplitterType<?, ?>> list = new ArrayList<>(); 

    private class SplitterType<T, V> { 

     private final Class<T> key1; 
     private final Class<V> key2; 
     private final Class<? extends Splitter<T, V>> clazz; 

     private SplitterType(Class<?> key1, Class<?> key2, Class<? extends Splitter<T, V> clazz) { 
      this.key1 = key1; 
      this.key2 = key2; 
      this.clazz = clazz; 
     } 

     private boolean matches(Class<?> key1, Class<?> key2) { 
      return this.key1 == key1 && this.key2 == key2; 
     } 
    } 

    public <T, V> void put(Class<T> key1, Class<V> key2, Class<? extends Splitter<T, V> clazz) { 
     list.add(new SplitterType<T, V>(key1, key2, clazz)); 
    } 

    public <T, V> Splitter<T, V> get(Class<T> key1, Class<V> key2) { 
     for (SplitterType<?, ?> type : list) { 
      if (type.matches(key1, key2)) { 
       try { 
        return ((SplitterType<T, V>) type).clazz.newInstance(); 
       } catch (Exception e) { 
       } 
      } 
     } 
     return null; // not found 
    } 
} 

然後,你可以只是做:

SplitterMap map = new SplitterMap(); 
map.put(Company.class, Department.class, CompanySplitterImpl.class); 
Splitter<Company, Department> splitter = map.get(Company.class, Department.class); 
0

首先我假設你想要類似

Splitter<Company, Department> s = Splitters.getSplitter() 

這也不是沒有反射更多鈔票,因爲

  1. 類型擦除
  2. 返回類型重載在Java中尚未公佈

其次你濫用FactoryMethod模式。這應該看起來更像這樣:

interface Splitter<T, V> { 
    V[] split(T arg); 
} 

interface SplitterFactory { 
    <T, V> Splitter<T, V> getSplitter(); 
} 

class CompanySplitterFactory implements SplitterFactory { 
    @Override 
    public Splitter<Company, Department> getSplitter() { 
     return new CompanySplitterImpl(); 
    } 
} 
相關問題