假设我有一个学生,如下所示:
public class Person {
String name;
int age;
}和一些子类,例如
public class Student extends Person {
// extra fields and methods
}
public class Teacher extends Person {
// extra fields and methods
}现在,考虑到对于某些应用程序,我需要为每个person实例分配一个整数id,但我不想扩展Person接口以在那里添加getId()和一个保存id的字段。一个简单的解决方案是使用一个包装器,如:
public class PersonWrapper extends Person {
public PersonWrapper(Person p, int id) { // assign the id and other fields }
public int getId() { return id; }
}这样,客户端代码仍然可以与person接口一起工作,并且包装的人员可以被视为Person。这种方法的问题在于,PersonWrapper是Person的子类,而不是教师或学生的子类,这样的代码无法工作:
Teacher t = new PersonWrapper(teacher, 1);
t.giveGrade();当然,可以为Person的所有子类创建具体的包装器类型,但我想知道是否有更优雅的解决方案。理想的解决方案是这样的:
public class PersonWrapper<T extends Person> extends T因此,任何PersonWrapper都是它封装的类型的子类,但在Java中是不可能的,我怀疑这种定义在任何语言中都是不可能的。
在任何情况下,我如何为子类分配In而不更改与person及其子类一起工作的客户端代码,而不为每个子类创建一个具体的包装器?
发布于 2014-12-17 19:25:59
你说得对,你不能做你想做的事。假设您不能将具体的类更改为(例如,Student extends Person implements Identifiable ),最好的方法是将包装器真正视为包装器,并有一个返回其不同元素的getter:
public class Wrapper<T> {
private final T item;
private final int id;
...
public int getId() { return id }
public T getItem() { return item; }
}使用起来有点麻烦,因为您必须做一些类似wrapper.getItem().giveGrade()的事情,而不仅仅是wrapper.giveGrade()。这也意味着您不能将包装器塞进List<Teacher>中,然后再将其降到TeacherWrapper中--但这有点脆弱,而且通常有更好的方法来实现您想要的结果。在大多数情况下,这种“纯”包装方法可以做您想做的事情。
请注意,我甚至没有T extends Person。如果包装类不需要使用任何Person方法,那么人工限制泛型没有什么好处。无论哪种方式,呼叫站点都会受到限制。一个不同之处是,如果调用站点有一个Wrapper<?>,那么我的代码将只允许您以Object的形式获取该项,而限制性更强的T extends Person将允许您以Person的形式获取该项。
发布于 2014-12-17 19:20:18
包装器不一定需要扩展到包装的类。所以,只需使用PersonWrapper<T extends Person>
public class PersonWrapper<T extends Person> {
T person;
int id;
public PersonWrapper(T person, int id) {
this.person = person;
this.id = id;
}
//getters and setters...
}另外,一个类只能在编译时从另一个类扩展,因此这个PersonWrapper不可能同时从Student和Teacher扩展,这使得您所要寻找的内容不可能实现。
唯一的解决方案是使用像cglib这样的库动态创建代理类。例如,当需要动态地向类添加功能时,Spring为类创建代理,例如为方法或整个类添加事务管理。
发布于 2014-12-17 19:31:20
这个问题的常见解决方案是使Person成为一个interface。
interface Person {
public String getName();
public int getAge();
}
class ActualPerson implements Person {
private final String name;
private final int age;
ActualPerson(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String getName() {
return name;
}
@Override
public int getAge() {
return age;
}
}
class PersonWithId implements Person {
private final Person person;
private final int id;
PersonWithId(Person person, int id) {
this.person = person;
this.id = id;
}
@Override
public String getName() {
return person.getName();
}
@Override
public int getAge() {
return person.getAge();
}
}不要害怕太多的代码--与你花在后悔的时间相比,编写代码的时间是微不足道的--一开始你没有正确地写代码。老家伙,2014
https://stackoverflow.com/questions/27533138
复制相似问题