2015-01-01 16 views
2

我正在將C#項目遷移到java。如何創建一個工廠,它根據Java中的接口類型創建類?

在C#項目中,我有一個工廠類在類型和創建適當類型的委託之間存放字典。

我露出一個通用的方法:

T Create<T>() 

因此,用戶可以寫:

var someObject = factory.Create<ISomeInterface>(); 

Create方法的代碼是一樣的東西:

return (T)dictionary[typeof(T)](); 

的問題是,如何我可以在Java(版本7)中做類似的事嗎?

非常感謝任何人的幫助!

+0

類型都可以通用? –

+0

不,唯一允許的類型是從一些基本接口繼承的接口。 (有一個約束 - 其中T:廣積) – AntonKam

回答

3

在java中,泛型類型參數信息在運行時不可用。因此,在Create()方法是不可能的,從類型參數T獲得相應的Class對象如果你想有這樣的工廠,你可以有一個類型的提供者接口

public interface IProvider<T extends IBase> { 
    T getInstance(); 
} 

然後用HashMap<Class<? extends IBase>, IFactory<? extends IBase>>維護工廠清單。所以,你可以調用下面的方法來獲得一個新的實例:

private HashMap<Class<? extends IBase>, IFactory<? extends IBase>> map; 

@SuppressWarnings("unchecked") 
public <T> T create(Class<T> type) { 
    return (T) map.get(type).getInstance(); 
} 

要使用create(Class<?>)方法,例如,你怎麼稱呼它,如下所示:

ISomeInterface someObject = create(ISomeInterface.class); 

請注意,這是你的責任,以確定密鑰類型與工廠的返回類型map匹配,否則將引發ClassCastException。

如果您不需要創建的類型擴展爲IBase,只需省略代碼片段中的所有extends IBase即可。

這裏有一個完整的例子:

package com.example.playground; 

import java.util.HashMap; 

public class TypeFactory { 

    public interface IBase { } 

    public interface IProvider <T extends IBase> { 
     T getInstance(); 
    } 

    private HashMap<Class<? extends IBase>, IProvider<? extends IBase>> registry = 
      new HashMap<>(); 

    public <T extends IBase> void addProvider(Class<T> type, IProvider<T> provider) { 
     registry.put(type, provider); 
    } 

    @SuppressWarnings("unchecked") 
    public <T extends IBase> T create(Class<T> type) { 
     return (T) registry.get(type).getInstance(); 
    } 

    public static void main(String[] args) { 
     TypeFactory factory = new TypeFactory(); 

     factory.addProvider(ISomeInterface.class, new IProvider<ISomeInterface>() { 
      @Override 
      public ISomeInterface getInstance() { 
       return new ISomeInterface() { 
        @Override 
        public String toString() { 
         return "I'm a class that implements ISomeInterface"; 
        } 
       }; 
      } 
     }); 

     ISomeInterface obj = factory.create(ISomeInterface.class); 
     System.out.println(obj); 
    } 

} 

interface ISomeInterface extends TypeFactory.IBase { } 
0

只要您要在IDictionary(或Java中的Map)中存儲的類型沒有類型參數,那麼您就沒問題,並且您可以輕鬆完成類似於C#版本的操作。我決定讓Factory的所有成員都是靜態的,但是您可以使用實例方法create來做同樣的事情。

public final class Factory { 

    private Factory() {} 

    private static interface InnerFactory<T> { 
     T produce(); 
    } 

    private static final class StringFactory implements InnerFactory<String> { 
     @Override 
     public String produce() { 
      return "Random String " + Integer.toString(new Random().nextInt()); 
     } 
    } 

    private static final class IntegerFactory implements InnerFactory<Integer> { 
     @Override 
     public Integer produce() { 
      return new Random().nextInt(); 
     } 
    } 

    private static final Map<Class<?>, InnerFactory<?>> map = new HashMap<Class<?>, InnerFactory<?>>(); 

    private static <T> void put(Class<T> clazz, InnerFactory<T> innerFactory) { 
     map.put(clazz, innerFactory); 
    } 

    static { 
     put(String.class, new StringFactory()); 
     put(Integer.class, new IntegerFactory()); 
    } 

    public static <T> T create(Class<T> clazz) { 
     return clazz.cast(map.get(clazz).produce()); 
    } 
} 

您現在可以從別處撥打Factory.create(String.class)。如果你嘗試並且在T類型中有一個類型參數的情況下做同樣的事情,那麼Java就會崩潰。然後它變得更加複雜,因爲由於類型擦除,List<String>.class等表達式不是合法代碼。

+0

我覺得在OP C#代碼意味着他們要創建給定類型的新對象時被調用的函數,而不是現有的對象。 – RealSkeptic

+0

@RealSkeptic好吧,決定不要這麼懶惰和更新代碼。 –