0
public class Person implements Roles{

    private String id;
    private String name;
    private String[] skills;
    private List<Note> notes;

    public Person(String id, String name, String[] skills) {
        this.id = id;
        this.name = name;
        this.skills = skills;
        this.notes = new ArrayList<Note>();
    }

    public String getName() {
        return this.name;
    }

    public String getId() {
        return this.id;
    }

    public String[] getSkills() {
        return this.skills;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSkills(String[] skills) {
        this.skills = skills;
    }

    public void addNote(String note, String authorName) {
        notes.add(new Note(authorName, note));
    }

    public String listNotes() {
        String result = this.name + " - " + this.id;
        for (Note note: notes) {
            result += "\n" + note.toString();
        }
        return result;
    }

    @Override
    public String toString() {
        String result = this.name + " - " + this.id;
        Arrays.sort(skills);
        for (String skill: skills) {
            result += "\n- " + skills;
        }
        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if (o.getClass() != this.getClass()) {
            return false;
        }
        Person Person2 = (Person) o;
        return this.id.equals(Person2.getId());
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}
public class Student extends Person implements Roles {
    
    private String registration;
    private int year;

    public Student(String id, String name, String registration, int year, String[] skills) {
        super(id, name, skills);
        this.registration = registration;
        this.year = year;
    }
    
    @Override
    public String toString() {
        String result = super.name + " - " + super.id + "\nStudent - " + this.registration + " - " + this.year;
        Arrays.sort(skills);
        for (String skill: skills) {
            result += "\n- " + skill;
        }
        return result;
    }
    
    @Override
    public String listNotes() {
        String result = super.name + " - " + super.id + "\nStudent - " + this.registration + " - " + this.year + "\nNotes:";
        for (Note note: notes) {
            result += "\n" + note.toString();
        }
        return result;
    }
}
public class Teacher extends Person implements Roles{
    
    private String number;
    private String[] subjects;

    public Teacher(String id, String name, String number, String[] subjects, String[] skills) {
        super(id, name, skills);
        this.number = number;
        this.subjects = subjects;
    }
    
    @Override
    public String toString() {
        String result = this.name + " - " + this.id + "\nTeacher - " + this.number + " - ";
        
        for (int i = 0; i <= subjects.length - 1; i++) {
            if (i == subjects.length - 1) {
                result += subjects[i];
                break;
            }
            
            result += subjects[i] + ", ";
        }
        Arrays.sort(skills);
        for (String skill: skills) {
            result += "\n- " + skill;
        }
        return result;
    }
    
    @Override
    public String listNotes() {
        String result = this.name + " - " + this.id + "\nTeacher - " + this.number + " - ";
        
        for (int i = 0; i <= subjects.length - 1; i++) {
            if (i == subjects.length - 1) {
                result += subjects[i] + "\n:";
                break;
            }
            
            result += subjects[i] + ", ";
        }
        
        for (Note note: notes) {
            result += "\n" + note.toString();
        }
        return result;
    }
}

The system must be able to register people, students and teachers. I created a superclass Person with Student and Teacher subclasses, and an interface to store in a people map.

And now I need a way to change the roles of those already registered people, like a person becoming a teacher, or a student being out of a role.

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
Tawk
  • 1

1 Answers1

0

I need a way to change the roles of those already registered people, like a person becoming a teacher, or a student being out of a role.

Before I answer your question, I would like to point out a few key design mistakes. (you can skip ahead, but highly discouraged)

  1. You do not need to implement the Roles interface multiple times in your Student and Teacher classes, as your superclass Person already did that.

As Federico said in this comment:

This is a weird design. Why is Role an interface? A person "has a role", not "is a role".

  1. As Federico said above, Person class should not be inheriting from the Roles interface, as that indicates that a person "is a role", not "has a role". Your Person class should be referencing Roles instead (you can read more about inheritance vs composition).

  2. Furthermore, I do not think that Roles is suitable as an interface in your context. An enum or a set of static constants seems more appropriate here.

To answer your question. By fixing the key mistakes pointed out above, adding an additional check, a custom exception, and a secondary constructor; you will get presumingly what you wanted.

Here is the bare version of your classes for the sake of simplicity, the rest can be easily added in.

public enum Role {
    NONE,
    STUDENT,
    TEACHER
}
public class UnrelatedRoleException extends RuntimeException {
    private static final String EXCEPTION_MESSAGE = "%s cannot be casted %s!";

    public UnrelatedRoleException(final Class<? extends Person> from, final Class<? extends Person> to) {
        super(String.format(EXCEPTION_MESSAGE, from.getSimpleName(), to.getSimpleName()));
    }
}
public class Person {
    private Role role;

    public Person() {
        this(Role.NONE);
    }

    public Person(final Role role) {
        this.role = role;
    }

    protected Person(final Person person) {
        if (!isApplicable(person.role)) {
            throw new UnrelatedRoleException(this.getClass(), this.getClass());
        }
    }

    /**
     * @param role the updated role
     */
    public void setRole(final Role role) {
        this.role = role;
    }

    /**
     * @return the person role
     */
    public Role getRole() {
        return role;
    }

    /**
     * @param role the role to check against
     *
     * @return true if the role is compatible with {@link Person}
     */
    public boolean isApplicable(final Role role) {
        return true;
    }
}
public class Student extends Person {
    public Student() {
        super(Role.STUDENT);
    }

    public Student(final Person person) {
        super(person);
    }

    @Override
    public boolean isApplicable(final Role role) {
        return role == Role.STUDENT;
    }
}
public class Teacher extends Person {
    public Teacher() {
        super(Role.TEACHER);
    }

    public Teacher(final Person person) {
        super(person);
    }

    @Override
    public boolean isApplicable(final Role role) {
        return role == Role.TEACHER;
    }
}

This is how it can be used:

public class Main {
    public static void main(String[] args) {
        final Person person = new Person();

        // updating the person's role to Student
        person.setRole(Role.STUDENT);
        final Student student = new Student(person);

        // updating the person's role to TEACHER
        person.setRole(Role.TEACHER);
        final Teacher teacher = new Teacher(person);
    }
}

The way this is designed:

  1. Person instance can be constructed with Role.NONE as the default role or pass down your own Role.

  2. Person will be treated as the common type between Student and Teacher. Therefore, it will be safe to use.

  3. There are two ways to retrieve an instance of Student and Teacher.

    3.1. If you have an instance of Person, change the Person's role to Role.STUDENT/Role.TEACHER, and pass down the Person instance to Student/Teacher to retain the data.

    3.2. Otherwise, create a new instance of Student/Teacher.

There is something to note: when you add the relevant methods to the subclasses of Person, I urge you to include a check that checks if the role persists with the current class (via #isApplicable(role)), and throw an unchecked exception (checked vs unchecked exceptions) if the role is no longer relevant.

Otherwise, the subclasses' role can be changed to something not relevant to the class, and presumingly break your requirement; as you should not be able to process duties that are no longer relevant to your role.

Feel free to ask any questions that you may have.