【问题标题】:Java, is it possible to 'convert' object from subclass to object from superclassJava,是否可以将子类中的对象“转换”为超类中的对象
【发布时间】:2011-11-01 21:34:50
【问题描述】:

我有两个班级 Student 和 Tutor。 Tutor 基本上是一个拥有facultyID 的学生(Tutor 扩展了Student)。合同完成后,他又回到了学生时代。那么我可以以某种方式将他转换回他的“以前的”学生名单吗?

【问题讨论】:

  • 您可能根本不应该使用继承来建模这种关系。根据您的简短描述,您可能需要考虑创建一个 Tutor 包装器,该包装器在构建时需要一个学生。然后,当合同完成时,您可以简单地让对包装器的引用超出范围并继续直接使用 Student 实例。
  • 您能否为您的问题提供更多背景信息?恕我直言,这实际上取决于您要实现的目标。也许添加一个boolean isTutor; 成员或者简单地保留一个也是导师的学生名单就足够了。无需仅仅因为可以就使用 OO 模式对所有内容进行建模。
  • @kritzikratzi 我喜欢你的评论“没有必要用 OO 建模所有东西......只是因为你可以”。完全同意!

标签: java object subclass superclass


【解决方案1】:

你真正想做的是使用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 对象的引用,但这取决于您将如何与Student 和Tutor 对象进行交互,以及您想要编码的方式.

【讨论】:

    【解决方案2】:

    我认为,这尖叫着包含和接口编程。

    这个怎么样:

    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 导师记录。

    另一方面,学生的记录仍将在 Central Services 中可用。

    【讨论】:

      【解决方案3】:

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

      一些替代方案:

      • Student 一些构造函数,该构造函数接受另一个Student 实例并复制相关字段。所谓的复制构造函数。这样,您就可以轻松地基于您的 Tutor 创建一个新的 Student 实例,然后改用它。
      • 如果重要的是保留实际实例而不是创建一些副本(也许您在各处都保留了引用),最好将角色与类分开。制作一些FacultyMember 类或其他东西,然后将StudentTutor 变成角色。然后您可以稍后更改FacultyMember 的角色。

      【讨论】:

        【解决方案4】:

        您可以强制将 Tutor 转换为 Student,以便您的代码在编译时将他视为学生,但该对象仍将是 Tutor,因此调用任何覆盖的方法都会导致 Tutor 类的版本为调用。

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

        由于您发现需要进行这种转换,您可能需要重新考虑类结构。例如,可能 Student 和 Tutors 都应该只是 Person,每个 Person 都可以有 Student 或 Teacher 的角色。

        【讨论】:

        • 您能详细说明一下吗?我不知道该怎么做?
        • @vedran:如果您想编辑您的答案以提供一些您当前的代码,并更完整地解释您通过将一个人从一种类型转换为另一种类型来实现的目标,我可以给你一些更好的反馈。
        【解决方案5】:

        您可以在 Tutor 上编写类似 TutorToStudent() 的方法,然后从您的 Tutor 创建一个新学生。如果你施放,你最终会得到对象仍然是导师。

        在这种情况下,您也可以考虑放弃继承,只使用一个标志来指示该学生是否是导师。

        【讨论】:

        • 但是如果你有一个学生集合,它仍然会保存旧的导师,而不是新的普通学生。
        • @glowcoder:是的,但对于大多数仍保持继承层次结构并试图以某种方式将 Tutor 转变为 Student 的解决方案来说,这是正确的。像任何解决方案一样,它不能解决所有情况,显然需要额外的编码来解决您提到的情况。
        • 是的,它确实适用于维护继承层次结构的解决方案。但“优先组合胜过继承”是一种很好的做法。拥有Student 角色和Tutor 角色并简单地拥有一个角色(或多个角色,如果使用列表)的实例(或列表)会更好。
        【解决方案6】:

        没有将他“转换”回学生的事情,他是导师,导师已经是学生。

        但是,对这个对象的访问进行泛化可能会有一些价值,这样你就只能使用student方法了。 java中有几个成语。

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

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

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

        【讨论】:

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

          2. 不是让 Tutor 直接扩展一个 Student,而是将 Tutor 特定的数据和行为变成一个 Decorator。或者更好的是,将 TutorStudent 都作为包含每个人的 People 对象的装饰器。这是执行此操作的正确方法之一。

          3. TutorStudent变成enum Type,并把这个字段保存在People中,这个比上面的更容易但是扩展性较差,这真的取决于Tutor之间差异的性质和学生。

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              猜你喜欢
              • 2013-09-03
              • 1970-01-01
              • 2011-02-24
              • 2014-03-09
              • 2021-01-23
              • 2012-07-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多