Week 09: Lab 5

Objectives

To explore small class hierarchies and polymorphism.

Exercise One

Building on the homework 4 exercise:

  • Extend (and modify as needed) your Student class from Lab 4 to create a ResearchStudent subclass. This class will need to have an additional field which is the name of the supervisor. Create a printInfo() method to print out the students’ fields and, in the case of the research student, their supervisor.

  • Write StudentTest class. Create an ArrayList of your Student and ResearchStudent classes. Add a mix of students and research students, then loop the ArrayList calling your printInfo() method.

  • Using the getClass() method, loop through ArrayList and print out whether the class is a Student or a ResearchStudent.

  • Repeat the exercise above, this time using the instanceof operator.

Exercise Two

Change Student into an abstract class by removing implementation of printInfo() method. Subclass it into Undegraduate and ResearchStudent accordingly. Modify the StudentTest class to work with Student type as elements of ArrayList. Make the code to print the list of students from the ArrayList without using the getClass() or instanceof but relying on polymorphism instead. Now the code is much simpler — examine it, convince yourself and learn to appreciate.

Further programming ideas: Visitor pattern

Imaging that your type hierarchy is large and deep — let’s not talk about students, but about employees in a gigantic organisation; very many different types of employee, all have the same number of overridden methods, declared in the abstract class Employee: printInfo(), calculateSalary(), paySupaContribution(), calculatePaidLeave() etc. There are Clerks, Managers, GeneralStaff, SeniorManagers, CEOs, Cleaners and so on. They all have different employment conditions, and different implementation of the above methods. Imagining also that the number of operations (methods) which we would like all our types to be able to perform is changeable, it can grow. To implement newly added methods in each and every subclass of Employee can quickly become quite a task.

There is a better way: to remove all methods from Employee and its subclasses and replace them with just one:

public abstract void accept(Visitor visitor);

Here, Visitor is a new type represented by an interface and a hierarchy of classes which implement it. The Visitor declares all the methods which were removed from the Employee hierarchy:

public void visit(Clerk c);
public void visit(Manager m);
public void visit(Cleaner c);
public void visit(GeneralStaff gs);
....

and the classes implementing Visitor, provide implementation bodies for all visit-methods:

class SalaryCalculator implements Visitor {
	private double salary;
	
	public void visit(Clerk c) {
		salary = c.getSalary();
	}
	public void visit(Manager m) {
		salary = c.getSalary() + c.getBonus();
	}
	......
	public double calculate() { return salary; }
}	

and similarly for all other Visitor classes. The Employee hierarchy classes all have the same implementation of the accept method:

public void accept(Visitor v) {
	v.visit(this);
}

When a client has a number of Employee objects and wants to call the same operation of them (to calculate total salary part of the budget, or print the organization roll, it would simply visit each employee with the salary calculator as follows:

SalaryCalculator sc = new SalaryCalculator();
employee.accept(sc);
total += sc.calculate();

The “invited” visitor will come to the caller object (this reference!) and do what was asked.

The visitor pattern is particularly effective when the visited (Employee here) hierarchy types are defined recursively (expression trees).

Confused? Intrigued? Learn more about the Visitor pattern (search the web), and try to use in the above “Student” (or “Employee”) examples. Do some more research and find out why the Visitor Pattern is such a double-edged sword — discover problems which its use may create that turn advantages into liabilities.

Updated:  27 Apr 2017/ Responsible Officer:  Head of School/ Page Contact:  Alexei Khorev