2009-11-06 76 views
0

我正在嘗試做一些我通常不會做的事情,這有點奇怪,但我想讓它工作。實質上,我有一個工廠必須通過調用具有不同類型數據的構造函數來創建對象(A和B在下面的代碼中採用不同的類型)。我似乎已經得到了我的自我堅持走下去的泛型路線(我需要的代碼是儘可能編譯時間類型安全)。我不反對以不同的方式編寫代碼(如果可能,我想保留工廠的想法,而且我不想添加轉換 - 因此「數據」參數不能是「對象」)。仿製藥調用構造函數

有關如何使用泛型修復代碼的任何想法或符合我的要求的替代方法?

(從技術上講,這是家庭作業,但是我的教練嘗試新的東西...所以它不是真正的功課:-)

public class Main2 
{ 
    public static void main(String[] args) 
    { 
     X<?> x; 

     x = XFactory.makeX(0, "Hello"); 
     x.foo(); 

     x = XFactory.makeX(1, Integer.valueOf(42)); 
     x.foo(); 
    } 

} 

class XFactory 
{ 
    public static <T> X<T> makeX(final int i, 
           final T data) 
    { 
     final X<T> x; 

     if(i == 0) 
     { 
      // compiler error: cannot find symbol constructor A(T) 
      x = new A(data); 
     } 
     else 
     { 
      // compiler error: cannot find symbol constructor B(T) 
      x = new B(data); 
     } 

     return (x); 
    } 
} 

interface X<T> 
{ 
    void foo(); 
} 

class A 
    implements X<String> 
{ 
    A(final String s) 
    { 
    } 

    public void foo() 
    { 
     System.out.println("A.foo"); 
    } 
} 

class B 
    implements X<Integer> 
{ 
    B(final Integer i) 
    { 
    } 

    public void foo() 
    { 
     System.out.println("B.foo"); 
    } 
} 

回答

1

我沒有看到讓它工作的方法。我真的不認爲它也可以。當調用makeX()函數時,調用代碼需要知道哪個整數參數對應於要傳入的數據類型。IOW,您的抽象首先是非常泄漏的,您實際上實現的是多態的基本形式,你也可以使用方法重載,即:

X makeX(String data) { 
    return new A(data); 
} 

X makeX(Integer data) { 
    return new B(data); 
} 

當然這是一個玩具問題,所有這一切。讓它工作的一種方法是讓客戶端知道實現類並添加一個通過反射實例化的參數。但我認爲這樣做會破壞目的。

+0

我其實並不是一個玩具,但是它並不是超級批評,我傾向於這樣做,或者將參數類型改爲僅僅是一個String,實際上這個字符串來自argv,代表一個文件名或者一個JDBC連接字符串。 – TofuBeer 2009-11-06 15:31:09

+0

好吧,我只是想與「我將如何實現這一點」,這基本上是什麼出來。 – wds 2009-11-06 15:51:06

1

我不認爲你想什麼沒有鑄造就可以做到。

擁有鑄造,你有兩個選擇

if(i == 0) 
     { 
      x = new A((Integer)data); 
     } 
     else 
     { 
      x = new B((String)data); 
    } 
} 

class A 
    implements X<String> 
{ 
    A(final Object s) 
    { 
    } 
} 

... 

class B 
    implements X<Integer> 
{ 
    B(final Object i) 
    { 
    } 
} 
+0

Casting(第一種方法)將不起作用 - 只是將編譯器錯誤移至x =部分。第二種方式只是我不會做的事情(它本質上是我試圖擺脫的)。 – TofuBeer 2009-11-06 04:09:46

+0

也是鑄造(第一種方式)將無法正常工作,因爲您可以傳遞一個Integer而不是String,它會編譯但在運行時失敗......我想我需要重新考慮整個事情。 – TofuBeer 2009-11-06 04:11:45

1

也許你能得到,同時保留了靜態類型安全和有懶的建築最接近的事是:

public static void main(String[] args) { 
    X<?> x; 

    x = aFactory("Hello").makeX(); 
    x.foo(); 

    x = bFactory(42).makeX(); 
    x.foo(); 
} 

private static XFactory aFactory(final String value) { 
    return new XFactory() { public X<?> makeX() { 
     return new A(value); 
    }}; 
} 

public static XFactory bFactory(final Integer value) { 
    return new XFactory() { public X<?> makeX() { 
     return new B(value); 
    }}; 
} 

interface XFactory() { 
    X<?> makeX(); 
} 

所以我們創建一個抽象工廠的實例,創建適當的實例機智h適當的論點。作爲工廠,該產品只按需求構建。

顯然有些東西不得不放棄。你期望XFactory.makeX(1, "Hello")能做什麼?

+0

仍然不會爲我想要的東西而工作 - 不得不調用2個方法,因爲它會將代碼放在工廠方法的後面 - 但我會稍微玩一下並看看。基本上我所追求的是一種方法,它可以用不同的參數創建不同的參數給構造函數,而不需要進行轉換......所以我希望「XFactory.makeX(1,」Hello「)在編譯時失敗。我只是想不出一種辦法,我確實想出了一些方法,但它們非常難看,我認爲我只是試圖推廣泛型太難 – TofuBeer 2009-11-06 04:25:41

0

這是不可能的,沒有鑄造。正如我在其他地方所說 - 泛型不會消除對鑄造的需求,但它們意味着您可以在一個地方進行所有鑄造。

在您所描述的設置中,工廠方法正是發生在所有發動機罩下工作的地方。這是在您的代碼告訴編譯器現場「我知道不知道這些類型,但做的,所以放鬆。

這是完全合法的爲你的工廠方法來知道,如果我= = 1,那麼數據必須是Integer類型,並通過強制轉換來檢查/強制執行此操作。