Java Tutorials Made Easy banner


Inheritance - The Company Project

The easiest way to learn how to utilize inheritance is through a real-world example. The company project has opportunities for inheritance. The problem is initially stated without the idea of inheritance, then is clarified several times during the process of implementing inheritance.

 

Problem Statement (version 1):

A company has programmers, factory workers, and supervisors.

A programmer is identified by his or her name and id. A programmer works a certain number of hours at a particular hourly rate. A programmer uses a particular programming language, and tracks the number of programs he or she has written.

A factory worker is identified by his or her name and id. A factory worker works a certain number of hours at a particular hourly rate. A factory worker is assigned to work in a factory, and this assignment does not change during his or her employment with the company.

A supervisor is identified by his or her name and id.  A supervisor works a certain number of hours at a particular hourly rate. A supervisor has a certain number of employees that report to him or her.

Note that programmers, factory workers, and supervisors each have a name, id, number of hours worked, and hourly rate. Rather than duplicate these fields in each, a superclass named Employee that contains these fields can be created.

                                   

A Programmer class which is a subclass of the Employee class can be defined. The Programmer class defines additional fields language and programsWritten.

                     

A FactoryWorker class is a subclass of the Employee class  that defines additional field factory.

                     

A Supervisor class is a subclass of the Employee class  that defines additional field numberOfEmployees.

                     

The Java source for the Employee class is listed below. It contains the private fields name, id, hours, and hourlyRate. It also contains accessors, mutators, and a constructor with parameters to initialize each field.

Listing 1 - Employee.java (version 1)

class Employee

{

    private String name;

    private int id;

    private double hours;

    private double hourlyRate;

    public Employee(String n, int i, double h, double r)

    {

        name = n;

        id = i;

        hours = h;

        hourlyRate = r;

    }

    public String getName() { return name; }

    public int getId() { return id; }

    public double getHours() { return hours; }

    public double getHourlyRate() { return hourlyRate; }

    public void setName(String n) { name = n; }

    public void setId(int i) { id = i; }

    public void setHours(double h) { hours = h; }

    public void setHourlyRate(double r) { hourlyRate = r; }

}

The Java source for the Programmer class is listed below. It contains the private fields language and programsWritten. The constructor initializes Employee fields by calling super with the first four parameters, sets language to the fifth parameter, then sets programsWritten to zero. The language field is declared final since it is only assigned in a constructor.

Listing 2 - Programmer.java (version 1)

public class Programmer extends Employee

{

    private final String language;

    private int programsWritten;

    public Programmer(String n, int i, double h, double r, String l)

    {

        super(n,i,h,r);

        language = l;

        programsWritten = 0;

    }

}

The Java source for the FactoryWorker class is listed below. It contains the private field factory. The constructor initializes Employee fields by calling super with the first four parameters, then sets factory to the fifth parameter. The factory field is declared final since it is only assigned in a constructor.

Listing 3 - FactoryWorker.java (version 1)

class FactoryWorker extends Employee

{

    private final String factory;

    public FactoryWorker(String n, int i, double h, double r,

                         String f)

    {

        super(n, i, h, r);

        factory = f;

    }

}

The Java source for the Supervisor class is listed below. It contains the private field numberOfEmployees. The constructor initializes Employee fields by calling super with the first four parameters, then sets numberOfEmployees to zero.

Listing 4 - Supervisor.java (version 1)

class Supervisor extends Employee

{

    private int numberOfEmployees;

    public Supervisor(String n, int i, double h, double r)

    {

        super(n, i, h, r);

        numberOfEmployees = 0;

    }

}

The problem statement can now be rewritten based on the class hierarchy defined previously..

 

Problem Statement (version 2):

A company has employees that are programmers, factory workers, and supervisors.

All employees have a name, an id, the number of hours worked, and their hourly rate. All employees are paid by multiplying the number of hours worked by their hourly rate and printing the result.

A programmer is a specific type of employee. Programmers use a particular language. Java programmers are initially paid $50 per hour, while those programming in other languages are initially paid $40 per hour.  A programmer also keeps track of the number of programs he or she has written. A programmer accounts for his or her hours by writing a program that takes a certain number of hours. This action adds to the number of hours worked and the number of programs written. If a programmer writes no programs, their pay is zero.

A factory worker is a specific type of employee. A factory worker is assigned to work in a factory, and this assignment does not change during his or her employment with the company. Factory workers are all initially paid $20 per hour, and by default, work 40 hours per week. A factory worker works a shift at his or her factory which may include overtime hours. If overtime hours are included, they are added to the number of hours worked.

A supervisor is a specific type of employee. The hourly rate and number of hours worked by a supervisor is variable. A supervisor keeps track of the number of employees he or she has evaluated. A supervisor evaluates an employee using a rating of 0, 1, or 2. If an employee’s rating is 2, then they receive a $1 per hour raise. If an employee’s rating is 0, then they receive a $1 per hour pay cut. If an employee’s rating is 1, their hourly rate stays the same.

This problem statement adds behaviors to the class hierarchy. Since “All employees are paid by multiplying the number of hours worked by their hourly rate and printing the result” , a method called pay can be added to the Employee class which operates on fields hours and hourlyRate.

public void pay()

{

    double wage = hours * hourlyRate;

    System.out.println("Pay employee:" + name + " id:" + id +

                       " $" + wage);

}

The new problem statement defines programmer behaviors that change the way Programmer objects are constructed. Since “Java programmers are initially paid $50 per hour, while those programming in other languages are initially paid $40 per hour”, the Programmer constructor does not need an argument for hourlyRate, since it is computed based on language.

        super(n,i,h,l.equals("Java")? 50.0:40.0);

Also, new logic is defined for the computation of hours and programsWritten for programmers:

“A programmer accounts for his or her hours by writing a program that takes a certain number of hours. This action adds to the number of hours worked and the number of programs written. If a programmer writes no programs, their pay is zero.”

This affects the constructor, since both hours and programsWritten are initially zero.

public Programmer(String n, int i, String l)

{

    super(n,i,0,l.equals("Java")? 50.0:40.0);

    language = l;

    programsWritten = 0;

}

The verb phrase “writing a program” suggests a method which would increment hours and programsWritten.

public void writeProgram(double h)

{

    programsWritten++;

    double currentHours = getHours();

    currentHours += h;

    setHours(currentHours);

    System.out.println(getName() +" writes a " + language +

                       " program that takes " + h +" hours.");

    System.out.print(getName() +" has written " + programsWritten +

                     " program");

    System.out.println( (programsWritten>1)? "s." : ".");

}

The new problem statement defines factory worker behaviors that change the way FactoryWorker objects are constructed. Since “Factory workers are all initially paid $20 per hour, and by default, work 40 hours per week.”, the FactoryWorker constructor needs no arguments for hours or hourlyRate, since these are specified by default.

public FactoryWorker(String n, int i, String f)

{

    super(n, i, 40.0, 20.0);

    factory = f;

}

Also, new logic is defined for the computation of hours for factory workers:

“A factory worker works a shift at his or her factory which may include overtime hours. If overtime hours are included, they are added to the number of hours worked.”

The verb phrase “works a shift” suggests a method which would add overtime to hours.

public void workShift(double overtime)

{

    double currentHours = getHours();

    currentHours += overtime;

    setHours(currentHours);

    System.out.println(getName() + " works " + getHours() +

                       " hours at the " + factory + " factory.");

}

The new problem statement defines supervisor behaviors that change the way Supervisor objects are constructed. Since “The hourly rate and number of hours worked by a supervisor is variable.”, hours and hourly rate will be initialized to zero, and no arguments will be provided for them in the Supervisor constructor .

public Supervisor(String n, int i)

{

    super(n, i, 0.0, 0.0);

    numberOfEmployees = 0;

}

Also, new logic is defined for the computation of the employees reporting to a supervisor:

“A supervisor keeps track of the number of employees he or she has evaluated. A supervisor evaluates an employee using a rating of 0, 1, or 2. If an employee’s rating is 2, then

they receive a $1 per hour raise. If an employee’s rating is 0, then they receive a $1 per hour pay cut. If an employee’s rating is 1, their hourly rate stays the same.”

The verb phrase “evaluates an employee” suggests a method which increments the numberOfEmployees field while modifying the hourly rate of the employee. Therefore, a reference to an Employee object must be passed as an argument to the method.        

public void evaluateEmployee(Employee e, int rating)

{

    numberOfEmployees++;

    double currentRate = e.getHourlyRate();

    switch (rating)

    {

        case 2:

            currentRate += 1.0;

            System.out.println(e.getName() + " gets a raise!");

            break;

        case 0:

            currentRate -= 1.0;

            System.out.println(e.getName() + " gets a pay cut!");

            break;                

    }

    e.setHourlyRate(currentRate);

    System.out.print(getName() + " has evaluated " +

                     numberOfEmployees + " employee");

    System.out.println( (numberOfEmployees>1)? "s." : ".");

}

The finals versions of the subclasses shown below also contain copy constructors.

Listing 5 - Employee.java (version 2)

public class Employee

{

    private String name;

    private int id;

    private double hours;

    private double hourlyRate;

    public Employee(String n, int i, double h, double r)

    {

        name = n;

        id = i;

        hours = h;

        hourlyRate = r;

    }

    public String getName() { return name; }

    public int getId() { return id; }

    public double getHours() { return hours; }

    public double getHourlyRate() { return hourlyRate; }

    public void setName(String n) { name = n; }

    public void setId(int i) { id = i; }

    public void setHours(double h) { hours = h; }

    public void setHourlyRate(double r) { hourlyRate = r; }

    public void pay()

    {

        double wage = hours * hourlyRate;

        System.out.println("Pay employee:" + name + " id:" +

                           id + " $" + wage);

    }

}

Listing 6 - Programmer.java (version 2)

public class Programmer extends Employee

{

    private final String language;

    private int programsWritten;

    public Programmer(String n, int i, String l)

    {

        super(n,i,0,l.equals("Java")? 50.0:40.0);

        language = l;

        programsWritten = 0;

    }

    public Programmer(Programmer p)

    {

        super(p.getName(),p.getId(),p.getHours(),p.getHourlyRate());

        language = p.language;

        programsWritten = p.programsWritten;

    }

    public void writeProgram(double h)

    {

        programsWritten++;

        double currentHours = getHours();

        currentHours += h;

        setHours(currentHours);

        System.out.println(getName() +" writes a " + language +

                           " program that takes " + h +" hours.");

        System.out.print(getName() +" has written "

                         + programsWritten +" program");

        System.out.println( (programsWritten>1)? "s." : ".");

    }

}

Listing 7 - FactoryWorker.java (version 2)

public class FactoryWorker extends Employee

{

    private final String factory;

    public FactoryWorker(String n, int i, String f)

    {

        super(n, i, 40.0, 20.0);

        factory = f;

    }

    public FactoryWorker(FactoryWorker f)

    {

        super(f.getName(),f.getId(),f.getHours(),f.getHourlyRate());

        factory = f.factory;

    }

    public void workShift(double overtime)

    {

        double currentHours = getHours();

        currentHours += overtime;

        setHours(currentHours);

        System.out.println(getName() + " works " + getHours() +

                           " hours at the " + factory + " factory.");

    }

}

Listing 8 - Supervisor.java (version 2)

public class Supervisor extends Employee

{

    private int numberOfEmployees;

    public Supervisor(String n, int i)

    {

        super(n, i, 0.0, 0.0);

        numberOfEmployees = 0;

    }

    public Supervisor(Supervisor s)

    {

        super(s.getName(),s.getId(),s.getHours(),s.getHourlyRate());

        numberOfEmployees = 0;

    }

    public void evaluateEmployee(Employee e, int rating)

    {

        numberOfEmployees++;

        double currentRate = e.getHourlyRate();

        switch (rating)

        {

            case 2:

                currentRate += 1.0;

                System.out.println(e.getName() + " gets a raise!");

                break;

            case 0:

                currentRate -= 1.0;

                System.out.println(e.getName() + " gets a pay cut!");

                break;                

        }

        e.setHourlyRate(currentRate);

        System.out.print(getName() + " has evaluated " +  

                         numberOfEmployees + " employee");

        System.out.println( (numberOfEmployees>1)? "s." : ".");

    }

}

The final problem statement introduces the company aggregate of employees.

 

Problem Statement (version 3):

Design a company that is made up of several employees with various roles:

All employees have a name, an id, the number of hours worked, and their hourly rate. All employees are paid by multiplying the number of hours worked by their hourly rate and printing the result.

A programmer is a specific type of employee. Programmers use a particular language. Java programmers are initially paid $50 per hour, while those programming in other languages are initially paid $40 per hour.  A programmer also keeps track of the number of programs he or she has written. A programmer accounts for his or her hours by writing a program that takes a certain number of hours. This action adds to the number of hours worked and the number of programs written. If a programmer writes no programs, their pay is zero.

A factory worker is a specific type of employee. A factory worker is assigned to work in a factory, and this assignment does not change during his or her employment with the company. Factory workers are all initially paid $20 per hour, and by default, work 40 hours per week. A factory worker works a shift at his or her factory which may include overtime hours. If overtime hours are included, they are added to the number of hours worked.

A supervisor is a specific type of employee. The hourly rate and number of hours worked by a supervisor is variable. A supervisor keeps track of the number of employees he or she has evaluated. A supervisor evaluates an employee using a rating of 0, 1, or 2. If an employee’s rating is 2, then they receive a $1 per hour raise. If an employee’s rating is 0, then they receive a $1 per hour pay cut. If an employee’s rating is 1, their hourly rate stays the same.

Write a class named Company with the following employees:

JoeJava                ID= 1        programmer        Java        rating=0

Write a program taking 30 hours

Writes another program taking 20 hours

SuzieCPlusPlus        ID= 2        programmer        C++        rating=2

Write a program taking 40 hours

Writes another program taking 20 hours

Fred                        ID=3        factory worker        factory=Widget rating=1

                        Works a shift with 5 hours overtime at the Widget factory

Mr. Big                ID=4        supervisor        works 20 hours  $100 per hour

Go through a single work, evaluation, and payment cycle.

The company can be modelled as an aggregate class with references to two Programmers, one FactoryWorker, and one Supervisor. The constructor accepts references to the Employee subclass objects as parameters and uses the copy constructors to avoid giving access to private members of the initial objects.

public class Company

{

    private Programmer JoeJava;

    private Programmer SuzieCPlusPlus;

    private FactoryWorker Fred;

    private Supervisor BigBoss;

    public Company(Programmer j, Programmer c, FactoryWorker f,

                   Supervisor s)

    {

        JoeJava = new Programmer(j);

        SuzieCPlusPlus = new Programmer(c);

        Fred = new FactoryWorker(f);

        BigBoss = new Supervisor(s);

    }

    ...

}

A  method is written to model the work cycle for all workers. The writeProgram method is called for Programmers with the number of hours each program takes to write. The workShift method is called for FactoryWorkers with the number of overtime hours worked.

public void work()

{

    JoeJava.writeProgram(30);

    JoeJava.writeProgram(20);

    SuzieCPlusPlus.writeProgram(40);

    Fred.workShift(5);

}

A  method is written to model the evaluation cycle for all workers. This calls BigBoss’s evaluateEmployee method on each worker with the corresponding rating.

public void evaluate()

{

    System.out.println();

    BigBoss.evaluateEmployee(JoeJava,0);

    BigBoss.evaluateEmployee(SuzieCPlusPlus,2);

    BigBoss.evaluateEmployee(Fred,1);

}

A  method is written to model the pay cycle for all employees. This calls the pay method of each Employee object. BigBoss’s number of hours worked and hourly rate need be set before he can

public void pay()

{

    System.out.println();

    JoeJava.pay();

    SuzieCPlusPlus.pay();

    Fred.pay();

    BigBoss.setHours(20);

    BigBoss.setHourlyRate(100.0);

    BigBoss.pay();        

}

The complete program is shown below.

Listing 9 - Company.java

public class Company

{

    private Programmer JoeJava;

    private Programmer SuzieCPlusPlus;

    private FactoryWorker Fred;

    private Supervisor BigBoss;

    public Company(Programmer j, Programmer c, FactoryWorker f,

                   Supervisor s)

    {

        JoeJava = new Programmer(j);

        SuzieCPlusPlus = new Programmer(c);

        Fred = new FactoryWorker(f);

        BigBoss = new Supervisor(s);

    }

    public void work()

    {

        JoeJava.writeProgram(30);

        JoeJava.writeProgram(20);

        SuzieCPlusPlus.writeProgram(40);

        Fred.workShift(5);

    }

    public void evaluate()

    {

        System.out.println();

        BigBoss.evaluateEmployee(JoeJava,0);

        BigBoss.evaluateEmployee(SuzieCPlusPlus,2);

        BigBoss.evaluateEmployee(Fred,1);

    }

    public void pay()

    {

        System.out.println();

        JoeJava.pay();

        SuzieCPlusPlus.pay();

        Fred.pay();

        BigBoss.setHours(20);

        BigBoss.setHourlyRate(100.0);

        BigBoss.pay();        

    }

    public static void main(String[] args)

    {

        Programmer jj = new Programmer("Joe",1,"Java");

        Programmer scpp = new Programmer("Suzie",2,"C++");

        FactoryWorker wk = new FactoryWorker("Fred",3,"Widget");

        Supervisor bb = new Supervisor("Mr. Big",4);

        Company company = new Company(jj, scpp, wk, bb);

        company.work();

        company.evaluate();

        company.pay();

    }

}

PROGRAM OUTPUT:

Joe writes a Java program that takes 30.0 hours.

Joe has written 1 program.

Joe writes a Java program that takes 20.0 hours.

Joe has written 2 programs.

Suzie writes a C++ program that takes 40.0 hours.

Suzie has written 1 program.

Fred works 45.0 hours at the Widget factory.

Joe gets a pay cut!

Mr. Big has evaluated 1 employee.

Suzie gets a raise!

Mr. Big has evaluated 2 employees.

Mr. Big has evaluated 3 employees.

Pay employee:Joe id:1 $2450.0

Pay employee:Suzie id:2 $1640.0

Pay employee:Fred id:3 $900.0

Pay employee:Mr. Big id:4 $2000.0

Company Project Modifications

The following topics were avoided in this tutorial in order to keep it as simple as possible and to focus on issues of inheritance. They are left as exercises for the reader.

1)- Polymorphism

You’ve probably noticed that the Programmer class’s writeProgram method and the FactoryWorker class’s workShift method can be replaced with methods named work that override the work method in the Employee class. The Programmer class’s work method can then be rewritten as follows:

public void work()

{

    JoeJava.work(30);

    JoeJava.work(20);

    SuzieCPlusPlus.work(40);

    Fred.work(5);

}

Furthermore, fields JoeJava, SuzieCPlusPlus, and Fred can be replaced with an array of Employee references. Additional workers can be added to the company and the role of each employee is not hard coded in the Company class. The following changes would be necessary:

2)- Protected Access

If the fields in the Employee class are given protected access, they can be operated on directly by the subclasses without using accessors or mutators.


This tutorial was written by:

Ralph Lecessi banner
CLICK HERE
to read books by Ralph