假设我的类中有两个构造函数:
public User (List<Source1> source){
...
}
public User (List<Source2> source) {
...
}
假设这两个构造函数都提供了关于用户的相同信息,并且都是为不同用例构造用户的同样有效的方法。
在Java语言中,由于类型擦除,您无法做到这一点-- Java不会接受两个参数为List<?>的构造函数。
那么,解决这个问题的方法是什么呢?什么是不过分杀伤力,但仍然尊重基本面向对象的解决方案?仅仅因为Java没有强大的泛型支持就必须构造一个工厂方法或其他接口,这似乎是错误的。
以下是我能想到的可能性:
1)接受List<?>
作为构造函数的参数,并在构造函数中解析您需要的逻辑类型,如果它不是任何可接受的类型,则抛出异常。
2)创建一个接受任一列表的类,构造适当的User对象,然后返回该对象。
3)在List<Source1>
和List<Source2>
周围创建可以传递给用户构造函数的包装器。
4)用两个类继承这个人的子类,除了构造函数,所有的功能都是继承的。一个的构造函数接受Source1,另一个接受Source2。
5)用一个构建器包装这个人,其中有两个不同的构建器方法,用于实例化的两个不同的数据源。
我的问题是:
1)这样做的需要是Java的缺陷,还是故意的设计决定?什么是直觉?
2)在维护良好的代码而不引入不必要的复杂性方面,哪种解决方案最强大?为什么?
这个问题是类似的:Designing constructors around type erasure in Java,但没有涉及细节,它只是建议了各种解决方法。
发布于 2012-06-07 19:03:34
通常的方法是使用factory methods
public static User createFromSource1(List<Source1> source) {
User user = new User();
// build your User object knowing you have Source1 data
return user;
}
public static User createFromSource2(List<Source2> source) {
User user = new User();
// build your User object knowing you have Source2 data
return user;
}
如果你只想使用Source1
或Source2
构造(即你没有默认的构造函数),你只需隐藏你的构造函数,强制客户使用你的工厂方法:
private User () {
// Hide the constructor
}
这个问题的出现是因为你不能以不同的方式命名构造函数,这就是如果这些是普通的方法,你将如何克服这个问题。因为构造函数名被固定为类名,所以这种代码模式是区分然后给出相同类型擦除的唯一方法。
发布于 2012-06-07 18:48:55
1:保持与擦除的向后兼容性。
2:你的类可以使用泛型吗?如下所示:
public class User<T> {
private List<T> whatever;
public User(List<T> source){
....
}
}
我不确定这是不是你所说的(2)
发布于 2012-06-08 01:55:25
基本的问题是,该语言是在泛型存在之前设计的(构造函数名称是固定的),因此它不能处理由于类型擦除而导致的冲突,这通常会通过重命名方法来区分它们。
一种不使用工厂方法的“变通办法”是添加另一个非类型化参数,以使编译器能够区分它们:
public User(List<Source1>, Source1 instance) {
// ignore instance
}
public User(List<Source2>, Source2 instance) {
// ignore instance
}
不过这有点差劲,因为你可以用任何东西(例如Integer
和String
,或者简单地让其中一个省略第二个参数)来替换这些额外的参数,它仍然可以工作。此外,额外的参数被忽略-它的存在只是为了区分构造函数。然而,它确实允许代码在不添加任何额外方法或特殊代码的情况下工作。
https://stackoverflow.com/questions/10937889
复制相似问题