Java, возможно ли «преобразовать» объект из подкласса в объект из суперкласса - PullRequest
8 голосов
/ 02 ноября 2011

У меня два класса ученик и репетитор. В основном, Tutor - это студент (Tutor extends Student), у которого есть facultyID. Как только его контракт завершен, он снова становится студентом. Так могу ли я каким-то образом преобразовать его в свой «предыдущий» список учеников?

Ответы [ 8 ]

5 голосов
/ 02 ноября 2011

Что вы действительно хотите здесь сделать, это использовать состав, а не наследование . Сохраните все свои объекты как тип 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, на каком пути вы хотите закодировать это .

4 голосов
/ 02 ноября 2011

Я думаю, это крики сдерживания и программирования интерфейса.

Как насчет этого:

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

Таким образом, ваш ученик остается учеником, даже если он переходит на позицию преподавателя.По истечении срока полномочий преподавателя вы просто собираете запись преподавателя.

Запись студента, с другой стороны, все еще будет доступна в центральных службах.

3 голосов
/ 02 ноября 2011

Как только вы создадите экземпляр некоторого типа (например, Tutor), это будет тот тип времени выполнения, который будет иметь этот экземпляр.Это больше нельзя изменить.

Некоторые альтернативы:

  • Дайте Student некоторый конструктор, который принимает другой экземпляр Student и копирует соответствующие поля.Так называемый конструктор копирования.Таким образом, вы можете легко создать новый Student экземпляр на основе вашего Tutor и затем использовать его вместо этого.
  • Если важно, чтобы фактический экземпляр был сохранен, а не создан какой-либо копией (возможно, вывезде хранились ссылки), было бы лучше отделить роль от класса.Создайте класс FacultyMember или что-то в этом роде и превратите Student и Tutor в роли.Затем вы можете изменить роль FacultyMember позже.
2 голосов
/ 02 ноября 2011

Вы можете привести Tutor к ученику, чтобы ваш код обрабатывал его как таковой во время компиляции, но объект останется Tutor, поэтому вызов любых переопределенных методов вызовет версию класса Tutor .

Единственный способ выполнить искомое преобразование - создать новый объект Student и присвоить ему все свойства, которыми обладает Tutor.

Поскольку вы обнаружите, что вам нужно выполнить это преобразование, вы можете переосмыслить структуру классов. Например, может быть, ученики и преподаватели должны быть просто людьми, и каждый человек может иметь роль ученика или учителя.

1 голос
/ 02 ноября 2011

Нет такой вещи, как «преобразование» его обратно в ученика, он наставник, а наставник уже есть ученик.

Тем не менее, может быть какое-то значение в обобщении доступа к этому объекту, так что вы можете использовать только метод ученика.Есть несколько идиом в Java для этого.

1) Вы можете использовать Student API исключительно в своем коде, за исключением части Tutor.

2) У вас может быть метод toStudent / toTutor для ваших объектов, который позволяет им возвращать объекты, специфичные для данной роли.

// Мои предпочтения 3) Вы можете использовать интерфейсы.Сделайте так, чтобы Tutor и Student были интерфейсами и создавали ваши объекты, используя реализацию интерфейса.Если вы ссылаетесь на объекты, используя минимальные интерфейсы, а не тяжелые шаблоны наследования, ваш код, вероятно, будет лучше масштабироваться в будущем.

1 голос
/ 02 ноября 2011
  1. Вы можете создать нового ученика с той же информацией, что и у наставника, и отбросить исходный объект. Либо с помощью конструктора копирования Student(Student original), либо метода Student toStudent() Это быстрый и грязный способ.

  2. Вместо того, чтобы заставлять Tutor напрямую расширять Студента, превращая Tutor специфические данные и поведение в Decorator . Или, что еще лучше, создайте декораторы Tutor и Student для объекта People, который включает всех. Это один из правильных способов сделать это.

  3. Превратите Tutor и Student в enum Type и удерживайте это поле в People, это проще, но менее расширяемо, чем выше, это действительно зависит от характера различий между Tutor и студент.

1 голос
/ 02 ноября 2011

Вы можете просто написать метод типа TutorToStudent() на Tutor и создать нового ученика из вашего Tutor.Если вы разыгрываете, вы получите объект, который все еще остается наставником.

Вы можете также рассмотреть возможность отказа от наследства в этом случае и просто иметь флаг, указывающий, является ли этот ученик репетитором.

1 голос
/ 02 ноября 2011

Вы не можете изменить тип объектов в Java. Вероятно, самый простой способ добиться этого - клонировать все параметры из Tutor в новый объект Student.

...