#java #object #subclass #superclass
#java #объект #подкласс #суперкласс
Вопрос:
У меня есть два класса Student и Tutor. Tutor — это, по сути, студент (Tutor расширяет Student), у которого есть facultyID. Как только его контракт будет завершен, он вернется к тому, чтобы быть просто студентом. Итак, могу ли я каким-то образом преобразовать его обратно в его «предыдущий» список учеников?
Комментарии:
1. Возможно, вам вообще не следует использовать наследование для моделирования этих отношений. Основываясь на вашем кратком описании, вы можете рассмотреть возможность создания оболочки Tutor, которая берет ученика во время разработки. Затем, когда контракт будет завершен, вы можете просто позволить ссылке на оболочку выпасть из области видимости и продолжить работу с экземпляром Student напрямую.
2. не могли бы вы дать немного больше контекста для вашего вопроса? имхо, это действительно зависит от того, чего вы пытаетесь достичь. возможно
boolean isTutor;
, достаточно добавить участника или просто сохранить список студентов, которые также являются преподавателями. не нужно моделировать все с помощью шаблонов OO только потому, что вы можете это сделать.3. @kritzikratzi Мне нравится ваш комментарий «Нет необходимости моделировать все с помощью OO… просто потому, что вы можете «. Не могу не согласиться!
Ответ №1:
То, что вы действительно хотите здесь сделать, это использовать композицию, а не наследование. Сохраните все ваши объекты как тип Student
, а затем временно назначьте поведение a 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, в зависимости от того, каким образом вы хотите это закодировать.
Ответ №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; };
}
Таким образом, ваш ученик остается учеником, даже если он переходит на позицию преподавателя. По истечении срока действия Tutor вы просто создаете запись tutor.
Запись студента, с другой стороны, по-прежнему будет доступна в центральных службах.
Ответ №3:
Как только вы создаете экземпляр некоторого типа (например, Tutor
), это тип среды выполнения, который будет иметь экземпляр. Это больше нельзя изменить.
Некоторые альтернативы:
- Дайте
Student
некоторый конструктор, который принимает другойStudent
экземпляр и копирует соответствующие поля. Так называемый конструктор копирования. Таким образом, вы могли бы легко создать новыйStudent
экземпляр на основе вашегоTutor
, а затем использовать его вместо этого. - Если важно сохранить фактический экземпляр, а не создавать какую-то копию (возможно, вы сохранили ссылки повсюду), было бы лучше отделить роль от класса. Создайте какой
FacultyMember
-нибудь класс или что-тоStudent
в этом роде иTutor
превратитесь в роли. Затем вы можете изменить рольFacultyMember
позже.
Ответ №4:
Вы можете использовать Tutor в качестве ученика, чтобы ваш код рассматривал его как такового во время компиляции, но объект останется Tutor, поэтому вызов любых переопределенных методов приведет к вызову версии класса Tutor.
Единственный способ выполнить «преобразование», которое вы ищете, — это создать новый объект Student и наделить его всеми свойствами, которые есть у Преподавателя.
Поскольку вы обнаруживаете, что вам нужно выполнить это преобразование, возможно, вам захочется переосмыслить структуру классов. Например, может быть, и ученики, и преподаватели действительно должны быть просто личностями, и каждый человек может играть роль Ученика или Учителя.
Комментарии:
1. Не могли бы вы уточнить это? Я не уверен, как это сделать?
2. @vedran: Если вы хотите отредактировать свой ответ, чтобы предоставить часть вашего текущего кода и более полное объяснение того, чего вы пытаетесь достичь, преобразуя человека из одного типа в другой, я могу дать вам лучшую обратную связь.
Ответ №5:
Вы могли бы просто написать метод, подобный TutorToStudent()
on Tutor, и создать нового ученика у своего преподавателя. Если вы приведете к тому, что объект все еще будет преподавателем.
Вы также можете рассмотреть возможность отказа от наследования в этом случае и просто иметь флаг, указывающий, является ли этот ученик преподавателем.
Комментарии:
1. Но тогда, если бы у вас была коллекция учеников, она все равно содержала бы старого преподавателя, а не нового обычного ученика.
2. @glowcoder: Верно, но это справедливо для большинства решений, которые по-прежнему поддерживают иерархию наследования и пытаются каким-то образом превратить Преподавателя в ученика. Как и любое решение, оно не решает все случаи, и, очевидно, потребуется дополнительное кодирование для учета случаев, подобных упомянутым вами.
3. да, это справедливо для решений, которые поддерживают иерархию наследования. Но хорошей практикой является «предпочтение композиции перед наследованием». Гораздо лучше иметь
Student
роль иTutor
роль и просто иметь экземпляр (или список) роли (или ролей, если используется список).
Ответ №6:
Нет такого понятия, как «превратить» его обратно в ученика, он — наставник, а наставник уже ЯВЛЯЕТСЯ учеником.
Однако может быть некоторая ценность в обобщении доступа к этому объекту, так что вы используете только метод student . Для этого в Java есть несколько идиом.
1) Вы можете использовать API Student исключительно в своем коде, за исключением части Tutor.
2) У вас может быть метод «toStudent / toTutor» для ваших объектов, который позволяет им возвращать объекты, специфичные для роли.
// Мои предпочтения 3) Вы можете использовать интерфейсы. Пусть Tutor и Student будут интерфейсами и создают ваши объекты с использованием реализации интерфейса. Если вы ссылаетесь на объекты, используя минимальные интерфейсы, а не тяжеловесные шаблоны наследования, ваш код, вероятно, будет лучше масштабироваться в будущем.
Ответ №7:
- Вы можете создать нового ученика с точно такой же информацией, что и у Преподавателя, и отказаться от исходного объекта. Либо с помощью конструктора копирования
Student(Student original)
, либоStudent toStudent()
с помощью метода Это быстрый и грязный способ. - Вместо того, чтобы заставлять Репетитора напрямую расширять ученика, превращая
Tutor
конкретные данные и поведение в Декоратора. Или еще лучше, сделайте иTutor
то, и другое, иStudent
декораторовPeople
объекта, который включает в себя всех. Это один из правильных способов сделать это. - Сделайте
Tutor
иStudent
в aenum Type
и удерживайте это полеPeople
, это проще, но менее расширяемо, чем вышеописанное, это действительно зависит от характера различий между преподавателем и учеником.
Ответ №8:
Вы не можете изменить тип объектов в Java. Вероятно, самый простой способ добиться вашего пути — это клонировать все параметры из Tutor в новый объект Student.