Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visitor Pattern for two arguments

We have interfaces/super classes: Student and Teacher.

Student has two implementations/sub clasees, ScienceStudent and PhysicalEducationStudent

Teacher has ScienceTeacher and PhysicalEducationTeacher.

We want to implement a method getMeetingPoint(Student s, Teacher t) which returns a place where they meet based on the type of Student and Teacher.

For example,

  • if it's a ScienceStudent and ScienceTeacher, they meet at Lab
  • if PEStudent and PETeacher, they meet on the Ground and
  • if it's a ScienceStudent and PETeacher, or vice versa, they meet at Cafeteria.

We can write a naive method, which checks using instanceof.

The problem is that this becomes complex when Teacher or Student gets extended, and tough to maintain. Something like this:

public class MeetingPointDecider {

    getMeetingPoint(Student s,Teacher t) {
        if(s instanceof ScienceStudent && t instanceof ScienceTeacher) {
            return "Lab";
        } else if (s instanceof PhysicalEducationStudent && t instanceof PhysicalEducationTeacher) {
            return "GRound";
        }
        .
        .
        .
    }
}

Another option is writing a factory, which accepts a Student and a Teacher and returns something like MeetingPointDecision [Ground or Lab], but the problem persists.

Is there any good pattern we can use, where we do not have to modify existing classes (or minimal modification) when a new class is added?

Say instanceof ScienceStudent we have ChemistryStudent, PhysicsStudent and ChemistryLab, PhysicsLab.

There is also a chance of adding more actions, which differs in implementation based on the Student and Teacher type ( Where Visitor is an option, but not sure how to implement with two deciding classes).

like image 682
pks Avatar asked May 26 '15 06:05

pks


People also ask

When would you use the visitor pattern?

Visitor design pattern is one of the behavioral design patterns. It is used when we have to perform an operation on a group of similar kind of Objects. With the help of visitor pattern, we can move the operational logic from the objects to another class.

How does the visitor pattern work?

The Visitor pattern represents an operation to be performed on the elements of an object structure without changing the classes on which it operates. This pattern can be observed in the operation of a taxi company. When a person calls a taxi company (accepting a visitor), the company dispatches a cab to the customer.

How many participants are there in the visitor pattern?

There are five major components of visitor pattern: Client: It is a class that acts as a consumer of the classes of the design pattern. It has the authority to access the data structure objects. It also instructs them to accept a Visitor that performs the appropriate processing.

What problems can the visitor design pattern solve?

In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures.


1 Answers

I would solve this using a map. The key should identify the teacher + student combination and the value would be the meeting point. for the key I would combine the class names. Here is the solution:

public class MeetingPointDecider
{
    public enum MeetingPoint { Ground, Lab, Cafeteria }
    private static MeetingPoint defaultmp = MeetingPoint.Cafeteria;
    private static Map<String, MeetingPoint> studentTeacherCombinations = new HashMap<>();

    static {
        studentTeacherCombinations.put(getMapKey(ScienceTeacher.class, ScienceStudent.class), MeetingPoint.Lab);
        studentTeacherCombinations.put(getMapKey(PETeacher.class     , PEStudent.class)     , MeetingPoint.Ground);
    }

    public static MeetingPoint getMeetingPoint(Student s,Teacher t)
    {
        String mapKey = getMapKey(t.getClass(), s.getClass()); 
        return studentTeacherCombinations.containsKey(mapKey) ? 
          studentTeacherCombinations.get(mapKey) : defaultmp; 
    }

    private static String getMapKey (Class<? extends Teacher> tCls, Class<? extends Student> sCls)
    {
        return tCls.getName() + "_" + sCls.getName();
    }
}

The logic part is in the static ctor where the map gets populated. It is easy to support future classes.

like image 81
Sharon Ben Asher Avatar answered Oct 26 '22 01:10

Sharon Ben Asher