Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java, is it possible to 'convert' object from subclass to object from superclass

I have two classes Student and Tutor. Tutor is basically a student (Tutor extends Student) who has facultyID. Once his contract is complete, he returns to being just a student. So can I somehow convert him back to his "previous" roll of student?

like image 900
vedran Avatar asked Nov 01 '11 21:11

vedran


4 Answers

What you really want to do here is use composition and not inheritance. Keep all your objects as type Student, and then temporarily assign the behaviour of a TutorRole as it is required to each instance of Student.

With this design your Student class will contain a property (member variable) of type TutorRole that you can add or remove at runtime. Adding an isTutor() method will allow you to detemine whether a Student is a Tutor at runtime in a clear and concise manner.

The TutorRole class will encapsulate the behaviour (i.e. methods) of being a 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

An alternative approach is to have a Tutor class contain a reference to a Student object, but it depends on how you are going to be interacting with the Student and Tutor objects on which way around you want to code this.

like image 106
Brad Avatar answered Oct 16 '22 22:10

Brad


I think, this screams containment and interface programming.

How about this:

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

This way, your Student remains a student, even if it moves to the Tutor position. When Tutor's term expires you just GC the tutor record.

Student's record, on the other hand will still be available in Central Services.

like image 23
Alexander Pogrebnyak Avatar answered Oct 16 '22 22:10

Alexander Pogrebnyak


Once you create an instance of some type (for example, Tutor), that's the runtime type that instance is gonna have. This can't be changed anymore.

Some alternatives:

  • Give Student some constructor that accepts another Student instance and copies over the relevant fields. A so-called copy constructor. That way, you could easily create a new Student instance based on your Tutor and then use that instead.
  • If it's important that the actual instance is kept rather than creating some copy (maybe you've kept references all over the place), it'd be best to separate role from class. Make some FacultyMember class or something and turn Student and Tutor into roles. Then you can change the role of a FacultyMember later on.
like image 37
G_H Avatar answered Oct 16 '22 23:10

G_H


You can cast the Tutor as a Student so your code treats him as such at compile time, but the object will remain a Tutor, so calling any overridden methods will cause the Tutor class's version to be called.

The only way to do the kind of "conversion" you're looking for is to create a new Student object and give it all the properties that the Tutor has.

Since you're finding that you need to do this conversion, you may want to re-think the class structure. For example, maybe both Students and Tutors should really just be Persons, and each Person can have the Role of Student or Teacher.

like image 43
StriplingWarrior Avatar answered Oct 16 '22 22:10

StriplingWarrior