Payroll-Inheritance01: Adding Types of Employees - Exercise

Contact Us or call 1-877-932-8228
Payroll-Inheritance01: Adding Types of Employees - Exercise

Payroll-Inheritance01: Adding Types of Employees

Duration: 30 to 45 minutes.

We wish to improve our payroll system to take account of the three different types of employees we actually have: exempt, nonexempt, and contract employees. Rather than use some sort of identifying code as a property, OOP makes use of inheritance to handle this need, since at runtime a type can be programmatically identified. So we will create three new classes that extend Employee:

  1. ExemptEmployee
  2. NonexemptEmployee
  3. ContractEmployee

In our company, exempt employees get a monthly salary, nonexempt an hourly rate that is multiplied by their hours, as do contract employees. There won't be any real difference between nonexempt and contract employees within their code. Realistically, in a real application, there would be, but, even if there weren't, it would still be a good idea to have separate classes, since the class type itself becomes a bit of information about the object. In the exception class hierarchy, there are many classes that have no internal differences; The multiple classes serve merely to identify the type of problem that occured.

We can inherit much of the logic from Employee, such as the pay rate fields and methods, as well as the name-related elements indirectly gained from Person. But, ContractEmployee and NonexemptEmployee will both add logic related to hours, and all three classes will override the getPayInfo method.

Also, the solution code builds upon the Person base class from the preceding example. You can either copy the Person.java file into your working directory and edit Employee.java to match, or just copy the set of files from the Java-Inheritance/Demos directory into your working directory and use those.

  1. Create three new classes, ExemptEmployee, NonexemptEmployee, and ContractEmployee that extend Employee
    • One possible approach is to copy the Employee.java file into a new file, ExemptEmployee.java, and modify as appropriate.
    • Then copy that into NonexemptEmployee.java and edit.
    • Then copy NonexemptEmployee.java into ContractEmployee.java and make the required changes.
  2. Add an hours field for non-exempt and contract employees, along with the associated get and set methods (note that the payRate field will hold a monthly amount for exempt and an hourly amount for nonexempt and contractors).
  3. Revise the getPayInfo method for each new class.
    • For all three, it should identify which type of employee it is.
    • For nonexempt and contract employees, calculate payRate * hours as the numeric value for their pay.
  4. Add constructors as you see fit, making use of calls to the appropriate super-constructors.
  5. There is a special main program already in the Exercises folder, Payroll4Inheritance01.java, that you can use to test your classes.

Solution:

Solutions/Payroll-Inheritance01/employees/ExemptEmployee.java
package employees;

public class ExemptEmployee extends Employee {
	
	public ExemptEmployee() {
	}
	public ExemptEmployee(String firstName, String lastName) {
		super(firstName, lastName);
	}
	public ExemptEmployee(String firstName,String lastName, int dept) {
		super(firstName, lastName, dept);
	}
	public ExemptEmployee(String firstName, String lastName, double payRate) {
		super(firstName, lastName, payRate);
	}
	public ExemptEmployee(String firstName, String lastName, int dept, 
				double payRate) {
		super(firstName, lastName, dept, payRate);
	}	
	public String getPayInfo() {
		return "Exempt Employee " + getId() + " dept " + getDept() + 
					 " " + getFirstName() + " " + getLastName() + 
					 " paid " + getPayRate();
	}
}

The primary thing to notice about this file is that it rewrites each constructor with one line to call the equivalent form of super.

Solution:

Solutions/Payroll-Inheritance01/employees/NonexemptEmployee.java
package employees;

public class NonexemptEmployee extends Employee {

	private double hours;
	
	public NonexemptEmployee() {
	}
	public NonexemptEmployee(String firstName, String lastName) {
		super(firstName, lastName);
	}
	public NonexemptEmployee(String firstName, String lastName, int dept) {
		super(firstName, lastName, dept);
	}
	public NonexemptEmployee(String firstName, String lastName, 
				double payRate, double hours) {
		super(firstName, lastName, payRate);
		setHours(hours);
	}
	public NonexemptEmployee(String firstName, String lastName, int dept, 
				double payRate, double hours) {
		super(firstName, lastName, dept, payRate);
		setHours(hours);
	}	

	public double getHours() {
		return hours;
	}
	public void setHours(double hours) {
		this.hours = hours;
	}

	public String getPayInfo() {
		return "Non-Exempt Employee " + getId() + " dept " + getDept() + 
					 " " + getFirstName() + " " + getLastName() + 
					 " paid " + getPayRate() * hours;
	}
}

In addition to rewriting the existing constructors, this class adds another that accepts hours, as well as appropriate methods to get and set that value.

Solution:

Solutions/Payroll-Inheritance01/employees/ContractEmployee.java
package employees;

public class ContractEmployee extends Employee {

	private double hours;
	
	public ContractEmployee() {
	}
	public ContractEmployee(String firstName, String lastName) {
		super(firstName, lastName);
	}
	public ContractEmployee(String firstName, String lastName, int dept) {
		super(firstName, lastName, dept);
	}
	public ContractEmployee(String firstName, String lastName, 
				double payRate, double hours) {
		super(firstName, lastName, payRate);
		setHours(hours);
	}
	public ContractEmployee(String firstName, String lastName, int dept, 
				double payRate, double hours) {
		super(firstName, lastName, dept, payRate);
		setHours(hours);
	}

	public double getHours() {
		return hours;
	}
	public void setHours(double hours) {
		this.hours = hours;
	}

	public String getPayInfo() {
		return "Contract Employee " + getId() + " dept " + getDept() + 
					 " " + getFirstName() + " " + getLastName() + 
					 " paid " + getPayRate() * hours;
	}
}

This class is virtually identical to NonexemptEmployee. Realistically, there would be differences due to benefits, dependents, etc.

Given the similarity between ContractEmployee and NonexemptEmployee, it might be worth refactoring to have a common base class for hourly employees, especially if there were situations where we would want to work with all hourly employees, regardless of type.

Solution:

Exercises/Payroll4Inheritance01.java
import employees.*;
import util.*;

public class Payroll4Inheritance01 {	
	public static void main(String[] args) {

---- C O D E   O M I T T E D ----
		ExemptEmployee ee = null;
		NonexemptEmployee ne = null;
		ContractEmployee ce = null;

		fName = KeyboardReader.getPromptedString("Enter first name: ");
		lName = KeyboardReader.getPromptedString("Enter last name: ");
		dept = KeyboardReader.getPromptedInt("Enter department: ");
		do {
			payRate = KeyboardReader.getPromptedDouble("Enter pay rate: ");
			if (payRate < 0.0) System.out.println("Pay rate must be >= 0");
		} while (payRate < 0.0);
		ee = new ExemptEmployee(fName, lName, dept, payRate);
		
		System.out.println(ee.getPayInfo());

		fName = KeyboardReader.getPromptedString("Enter first name: ");
		lName = KeyboardReader.getPromptedString("Enter last name: ");
		dept = KeyboardReader.getPromptedInt("Enter department: ");
		do {
			payRate = KeyboardReader.getPromptedDouble("Enter pay rate: ");
			if (payRate < 0.0) System.out.println("Pay rate must be >= 0");
		} while (payRate < 0.0);
		do {
			hours = KeyboardReader.getPromptedDouble("Enter hours: ");
			if (hours < 0.0) System.out.println("Hours must be >= 0");
		} while (hours < 0.0);
		ne = new NonexemptEmployee(fName, lName, dept, payRate, hours);

		System.out.println(ne.getPayInfo());

		fName = KeyboardReader.getPromptedString("Enter first name: ");
		lName = KeyboardReader.getPromptedString("Enter last name: ");
		dept = KeyboardReader.getPromptedInt("Enter department: ");
		do {
			payRate = KeyboardReader.getPromptedDouble("Enter pay rate: ");
			if (payRate < 0.0) System.out.println("Pay rate must be >= 0");
		} while (payRate < 0.0);
		do {
			hours = KeyboardReader.getPromptedDouble("Enter hours: ");
			if (hours < 0.0) System.out.println("Hours must be >= 0");
		} while (hours < 0.0);
		ce = new ContractEmployee(fName, lName, dept, payRate, hours);
		System.out.println(ce.getPayInfo());

	}
}
Next