具体类型的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){}
}