Overloaded methods that handle subclasses of some abstract class
Overloaded methods that handle subclasses of some abstract class
I have a generic Person
class, and two types of people Student
and Teacher
that extends the Person
class. I also have teaching sessions which will store a list of students and a list of teachers that will be in that session.
class Person {} class Student extends Person {} class Teacher extends Person {} class Session { List students = new ArrayList(); List teachers = new ArrayList(); // add a person to the teaching session. // They should be placed into the appropriate lists public void enroll(Person p) { if (p instanceof Student) students.add((Student) p) else if (p instanceof Teacher) teachers.add((Teacher) p) } }
The idea is that some other code will have a list of people and iterate the list to enroll them into the appropriate sessions as needed. However, the enroll
method currently explicitly checks the object's type, which to me is undesirable and seems like bad design.
I have tried writing the enroll
method like this using method overloading, which looks a lot cleaner
public void enroll(Student p) { students.add(p) } public void enroll(Teacher p) { teachers.add(p) }
but it seems like the code that iterates through the list of Person
objects would need to then figure out whether the current person is a student or teacher instance, and type-cast appropriately before passing it to an enroll
method.
Is there a way for me to design this so that I do not need to invoke instanceof
at any point in time in my own code?
Answer by Robe Elckers for Overloaded methods that handle subclasses of some abstract class
You can do what you propose with an overloaded method per concrete Person
implementation, and in addition to that add a Type to the List:
List students = new ArrayList<>(); List teachers = new ArrayList<>();
Then in your iteration logic you know the type.
Answer by Lee Meador for Overloaded methods that handle subclasses of some abstract class
You can turn it around:
class Session { StudentList students = new StudentList(); TeacherList teachers = new TeacherList(); // add a person to the teaching session. // They should be placed into the appropriate lists public void enroll(Person p) { p.addMe(students, teachers); } } public class StudentList extends ArrayList { } public class TeacherList extends ArrayList { } public abstract class Person { public abstract void addMe(StudentList sList, TeacherList tList); } public class Student extends Person { public void addMe(StudentList sList, TeacherList tList) { sList.add(this); } } public class Teacher extends Person { public void addMe(StudentList sList, TeacherList tList) { tList.add(this); } }
Answer by Mel Nicholson for Overloaded methods that handle subclasses of some abstract class
The simplest way to do this is to add an isTeacher()
method to the person class.
Here is a basic implemention (with the parts you already wrote left out)
abstract class Person { public abstract boolean isTeacher(); } class Teacher extends Person { public boolean isTeacher() { return true; } } class Student extends Person { public boolean isTeacher() {return false; } } abstract class Session { public void enroll(Person p) {
If you also want to avoid the typecast, try this...
abstract class Person { public abstract Teacher asTeacher(); public abstract Student asStudent(); } class Student extends Person { public Student asStudent() { return this; } public Teacher asTeacher() { return null; } } class Teacher extends Person { public Student asStudent() { return null; } public Teacher asTeacher() { return this; } } class Session extends Person { public void enroll(Person p) { Teacher t = p.asTeacher(); if (t != null) teachers.add(t); else students.add(p.asStudent()); } }
This implementation has a minor weakness that it assumes Teachers and Students are the only types of people, but extending it to multiple types is fairly straightforward.
Answer by Aaron Kurtzhals for Overloaded methods that handle subclasses of some abstract class
Session
needs to have an overloaded enroll method as in your question.Add an
abstract enroll
method toPerson
class that takesSession
as a parameterpublic abstract void enroll (Session s);
Teacher
andStudent
each overrideenroll
public void enroll (Session s) { s.enroll(this); }
Answer by Diego for Overloaded methods that handle subclasses of some abstract class
The issue with p instanceof Student
is that you change the behavior based on something that is not a method invocation, so future changes will be hard (ie. if you add another sub-class of Person).
There are a couple of ways to look at this design problem:
Why you need to create a hierarchy of
Person
? It's possible in your system that someone that is a student can be a teacher in another course? If that is the case, you have some information about a person, and what changes is the role of that person for a course. So is not convenient to use inheritance for that, use composition and create an object that represents the role of aPerson
in a course.You can add a
isTeacher
method, or use a visitor pattern to split the collection. That will be a little bit better than theinstanceof
. But in my opinion the problem is still in the incorrect class hierarchy.
For example, using "roles":
enum Role { TEACHER, STUDENT; } class Session { List enrollments = new ArrayList<>(); public void enroll(Person p, Role role) { enrollments.add(new SessionEnrollment(p, role)); } public List getTeachers() { List result = new ArrayList<>(); for (SessionEnrolment e : enrollments) { if (e.isTeacher()) { result.add(e.getPerson()); } return result; } } }
Using a isTeacher
method:
public void enroll(Person p) { if (p.isTeacher()) { teachers.add(p); } else { students.add(p); } }
As you can see having a isTeacher
method for all persons looks awkward. And the role solution reflects better the temporal property of being a student or teacher.
You can use a visitor, and it will save you from the ugly isTeacher
in Person
; but to me that solution is overcomplicated, and you'll translate the "uglyness" to the Visitor
interface.
Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72
0 comments:
Post a Comment