2011-11-01 93 views
8

我有两个类Student和Tutor。导师基本上是一名学生(导师延伸学生)谁拥有facultyID。一旦他的合同完成,他就回到只是一名学生。那么我能否以某种方式将他转回他以前的学生卷?Java,是否有可能将对象从子类转换为超类对象

+0

可能你不应该使用继承来模拟这种关系。根据您的简短描述,您可能需要考虑创建一个Tutor包装器,它在施工时需要一名学生。然后,当合同完成时,您可以简单地让对包装的引用超出范围,并继续直接与Student实例一起工作。 –

+2

你能否提供更多的背景给你的问题? imho它真的取决于你想要达到的目标。 也许增加一个'布尔isTutor;'成员或者干脆保留一个也是导师的学生列表就足够了。不需要仅仅因为可以用OO模式对所有东西进行建模。 – kritzikratzi

+0

@kritzikratzi我喜欢你的评论“没有必要用OO建模所有东西......只是因为你可以”。不能同意更多! – corsiKa

回答

5

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

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

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

/* 
* 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对象的引用,但是这取决于你将如何与学生进行互动,各地要编码这个导师在哪条路对象。

2

你可以转换作为学生的导师,所以你的代码在编译时对待他,但对象将保持一个导师,所以调用任何重写的方法将导致调用Tutor类的版本。

要做的那种“转换”,你正在寻找的唯一方法是创建一个新的学生对象,并给它所有的导师的属性。

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

+0

请您详细说明一下吗?我不知道该怎么做? – vedran

+0

@vedran:如果你想编辑你的答案来提供你当前的一些代码,并且更全面地解释你将一个人从一种类型转换为另一种类型所要达到的目标,我可以给你一些更好的反馈。 – StriplingWarrior

3

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

一些替代方案:

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

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

1

您可以在Tutor上写一个像TutorToStudent()这样的方法,并从您的导师中创建一个新学生。如果你演员,你会最终与对象仍然是一个导师。

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

+0

但是,如果你有一个学生集合,它仍然会保持老导师,而不是新的正规学生。 – corsiKa

+0

@ glowcoder:没错,但对于大多数仍然保持继承层次并试图以某种方式将Tutor转换为Student的解决方案。就像任何解决方案一样,它不能解决所有情况,显然需要额外的编码来解决像您提到的情况。 –

+0

是的,它适用于维护继承层次的解决方案。但是,“赞成组合继承”是一种很好的做法。拥有“学生”角色和“导师”角色要好得多,并且只需拥有角色的实例(或列表)(如果使用列表,则为角色)。 – corsiKa

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

  2. 而不是让导师直接扩展一个学生,使Tutor具体的数据和行为为Decorator的。或者更好的是,使TutorStudent包含所有人的People对象的装饰器。这是做这件事的正确方法之一。

  3. 充分利用TutorStudentenum TypePeople持有该领域,这是比上面更容易,但不易伸长,这真的取决于教师和学生之间的差异的性质。

1

有没有将他“转化”回学生,他是导师,而导师已经是学生的东西。

但是,通用化此对象的访问可能会有一些价值,因此您只能使用学生方法。在这里有几个Java的成语。

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

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

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

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; }; 
} 

这样一来,你的学生仍然是一个学生来说,即使它移动到导师的位置。当导师任期届满时,您只需GC导师记录。

另一方面,学生记录仍然可用于中央服务。

相关问题