2009-11-06 84 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类型,并通过强制转换来检查/强制执行此操作。