具体类型的Java包装器类子类
假设我有一个班级成员,如下所示:具体类型的Java包装器类子类,java,subclass,wrapper,Java,Subclass,Wrapper,假设我有一个班级成员,如下所示: 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 } 现在,考虑到一些应用程序,我需要给每个人实例分配一个整
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
}
现在,考虑到一些应用程序,我需要给每个人实例分配一个整数ID,但是我不想扩展<代码>人>代码>接口来添加GETIDER()和一个保持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扩展了
因此,任何PersonWrapper都是它所包装类型的子类,但在Java和I中是不可能的
怀疑这种定义在任何语言中都是不可能的
在任何情况下,我如何在不更改与person及其子类一起工作的客户端代码的情况下为子类分配ID,而不为每个子类创建具体的包装器?包装器不一定需要扩展到它所包装的类。所以,只需使用
PersonWrapper
:
公共类PersonWrapper{
T人;
int-id;
公共PersonWrapper(T个人,内部id){
这个人=人;
this.id=id;
}
//接球手和接球手。。。
}
另外,一个类只能在编译时从另一个类扩展,因此这个PersonWrapper
不可能同时从Student
和Teacher
扩展,这使得您所寻找的不可能
唯一的解决方案是使用类似的库动态创建代理类。例如,当需要向类动态添加功能时,Spring会为类创建代理,例如为方法或整个类添加事务管理。你说得对,你不能做你想做的事。假设您不能将具体类更改为,例如,
Student extends Person implements可识别的
,那么最好将您的包装器真正视为一个包装器,并使用一个返回其不同元素的getter:
public class Wrapper<T> {
private final T item;
private final int id;
...
public int getId() { return id }
public T getItem() { return item; }
}
公共类包装器{
私人期末考试项目;
私有最终int id;
...
public int getId(){return id}
public T getItem(){return item;}
}
这使用起来有点麻烦,因为您必须执行类似于wrapper.getItem().giveGrade()
的操作,而不仅仅是wrapper.giveGrade()
。这也意味着您不能将包装器放入列表
,然后再将其下放到TeacherWrapper
——但这有点脆弱,通常有更好的方法来完成您想要的。在大多数情况下,这种“纯”包装器方法可以满足您的需要
请注意,我甚至没有
t扩展Person
。如果包装器类不需要使用任何Person
方法,那么人工限制泛型就没有什么好处了。无论哪种方式,呼叫站点都将受到限制。一个区别是,如果呼叫站点有一个包装器
,那么我的代码只允许您以对象
的形式获取项目,而更严格的T extends Person
将允许您以Person
的形式获取该项,此问题的常见解决方案是使Person
成为接口
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
我希望我没有遗漏什么,但在我看来,包装器模式解决了您的问题:
public class Person implements IPerson{
String name;
int age;
public static void main(String[] args)
{
Teacher teacherWithID = new Teacher(new PersonWithID(new Person()));
Teacher teacherWithoutID = new Teacher(new Person());
}
}
interface IPerson{}
class Teacher implements IPerson{
public Teacher(IPerson personToBeWrapped){}
}
class Student implements IPerson{
public Student(IPerson personToBeWrapped){}
}
class PersonWithID implements IPerson{
public PersonWithID(IPerson personToBeWrapped){}
}
无论变量的类型是什么,都应该是最后一个包装器
包装器模式可以被认为是一种机制,允许您在运行时“扩展”类。因为这个原因,它也被称为装饰者。您的代码中有相互竞争的继承机制。(内置模式和模式)结果是无法键入变量。
如果您专门使用该模式,它会起作用。但我不希望我的客户每次看到该模式时都将其打开。PersonWrapper不是Person的子类型@Ali,你与第一个要求相矛盾:考虑到一些应用程序,我需要给每个人实例分配一个整数ID,但是我不能扩展<代码>人<代码>接口。假设这样,您的包装器不能从PersonWrapper
扩展。
public class Person implements IPerson{
String name;
int age;
public static void main(String[] args)
{
Teacher teacherWithID = new Teacher(new PersonWithID(new Person()));
Teacher teacherWithoutID = new Teacher(new Person());
}
}
interface IPerson{}
class Teacher implements IPerson{
public Teacher(IPerson personToBeWrapped){}
}
class Student implements IPerson{
public Student(IPerson personToBeWrapped){}
}
class PersonWithID implements IPerson{
public PersonWithID(IPerson personToBeWrapped){}
}