Java,是否有可能将对象从子类“转换”为超类中的对象

时间:2011-11-01 21:34:50

标签: java object subclass superclass

我有两个班级学生和导师。导师基本上是一名具有教师ID的学生(导师扩展学生)。一旦他的合同完成,他就会重新成为一名学生。那么我能以某种方式将他转回他的“前一卷”学生身上吗?

8 个答案:

答案 0 :(得分:5)

您真正想要做的是使用composition and not inheritance。将所有对象保持为Student类型,然后临时为TutorRole的每个实例分配Student的行为。

使用此设计,您的Student类将包含类型TutorRole的属性(成员变量),您可以在运行时添加或删除它。添加isTutor()方法可以让您在运行时以清晰简洁的方式确定学生是否是导师。

TutorRole类将封装作为导师的行为(即方法)。

/*
 * The TutorRole can be set at runtime
 */
public class Student {

    private String facultyId;

    private TutorRole tutorRole = null;

    public boolean isTutor() {
        return !(tutorRole == null);
    }

    public void doTutorStuff() {
        if(isTutor()) {
            tutorRole.doTutorStuff();
        }
        else {
            throw new NotTutorException();
        }
    }

    public void setTutorRole(TutorRole tutorRole) {
        this.tutorRole = tutorRole;
    }
}

/*
 * Ideally this class should implement a generic interface, but I'll keep this simple
 */
public class TutorRole {

    public void doTutorStuff() {
        // implementation here
    }
}

/*
 * Now let's use our classes...
 */
Student st = new Student(); // not a tutor
st.setTutorRole(new TutorRole()); // now a tutor
if(st.isTutor()) {
    st.doTutorStuff();
}
st.setTutorRole(null); // not a tutor anymore

另一种方法是让Tutor类包含对Student对象的引用,但这取决于您将如何与Student和Tutor对象进行交互。想要编码。

答案 1 :(得分:4)

我认为,这会遏制遏制和界面编程。

这个怎么样:

interface IStudent
{
  String getName();
  int getStudentId();
}

interface IFacultyMember
{
  int getFacultyId( );
}

class Student
  implements IStudent
{
  String name;
  int id;

  public String getName( ) { return name; }
  public int getStudentId( ) { return id; }
}

class Tutor
  implements IStudent, IFacultyMember
{
  Student student;
  int facultyId;

  public Tutor ( Student student, int facultyId )
  {
    this.student = student;
    this.facultyId = facultyId;
  }

  public String getName( ) { return student.getName( ); }
  public int getStudentId( ) { return student.getStudentId( ); }
  public int getFacultyId( ) { return facultyId; };
}

这样,即使您的学生转到辅导员职位,您的学生仍然是学生。当Tutor的学期到期时,你只需要GC导师记录。

另一方面,学生的记录仍将在中央服务中提供。

答案 2 :(得分:3)

一旦创建了某种类型的实例(例如,Tutor),那就是实例将拥有的运行时类型。这不能再改变了。

一些替代方案:

  • Student提供一些接受另一个Student实例的构造函数,并复制相关字段。一个所谓的复制构造函数。这样,您就可以根据Student轻松创建新的Tutor实例,然后再使用它。
  • 如果重要的是保留实际实例而不是创建一些副本(也许你已经在所有地方保留了引用),那么最好将角色与类分开。制作一些FacultyMember课程,然后将StudentTutor转换为角色。然后,您可以稍后更改FacultyMember的角色。

答案 3 :(得分:2)

你可以投射作为学生的导师,所以你的代码在编译时对待他,但是对象仍然是Tutor,所以调用任何被覆盖的方法将导致Tutor类的版本是调用。

您正在寻找的那种“转换”的唯一方法是创建一个新的Student对象并为其提供Tutor所具有的所有属性。

由于您发现需要进行此转换,因此您可能需要重新考虑类结构。例如,学生和导师可能真的只是个人,每个人都可以扮演学生或教师的角色。

答案 4 :(得分:1)

您无法在Java中更改对象类型。可能最简单的方法是将Tutor中的所有参数克隆到新的Student对象中。

答案 5 :(得分:1)

您可以在Tutor上编写类似TutorToStudent()的方法,并从您的导师中创建一个新学生。如果你投射你最终仍然是一个导师仍然是一个导师。

在这种情况下,您也可以考虑放弃继承权,并且只有一个标志,表明该学生是否是导师。

答案 6 :(得分:1)

  1. 您可以使用与教师完全相同的信息创建一个新学生,并丢弃原始对象。使用复制构造函数Student(Student original)Student toStudent()方法这是快速而肮脏的方式。

  2. 而不是让Tutor直接扩展学生,而是将Tutor特定数据和行为转换为 Decorator 。或者更好的是,制作包含所有人的Tutor对象的StudentPeople装饰器。这是执行此操作的正确方法之一。

  3. TutorStudent变为enum Type并在People中保留此字段,这比上述更容易但不易扩展,它真的取决于关于导师与学生之间差异的性质。

答案 7 :(得分:1)

没有将他“转换”给学生,他是导师,导师已经是学生。

但是,对此对象的访问进行通用化可能有一些价值,因此您只能使用student方法。 java中有几个习惯用法。

1)您可以在代码中专门使用Student API,但Tutor部分除外。

2)您可以为对象设置“toStudent / toTutor”方法,允许它们返回特定于角色的对象。

//我的偏好 3)您可以使用接口。让Tutor和Student都是接口,并使用接口实现构建对象。如果使用最小接口引用对象,而不是重量级继承模式,则代码将来可能会更好地扩展。