Background

This course project is designed to help you practice using your skills. Each week, you will learn important concepts. Then, you will apply these concepts to build an amazing course project over the next seven weeks. What's more, this project will have a Graphical User Interface (GUI) instead of using the console. This course project has two parts. For the first couple of weeks, you will be create a basic GUI and learn how to work with GUI controls while practicing basic programming concepts. After that, you will create an object oriented project.

Scenario

You have been hired as a consultant to create a basic Payroll System for a small business. The business wants to keep track of basic employee information and print paychecks for the employees every two weeks. Your client has some basic functionality in mind, such as the ability to add and remove employees, display basic employee information, and print paychecks. Maintenance is key! You realize that Object-Oriented programming will provide the most efficient application that is easy to maintain and update as needed. Let's get started!

Composition and Inheritance

Objectives

  • Integrate Employee class
  • Data hiding

Introduction

So far, your application can keep track of basic employee information. You can add and remove employees. The basic information is displayed efficiently by your listbox. However, the company offers a benefit to their employees. The company wants the application to track these benefits since the benefits are considered part of the basic employee information. Since we are using object-oriented programming techniques, it will be easy to "attach" the benefits to the employees. The employee object will be contain the benefits object. In OOP speak, the Employee object is composed of a Benefits object.

Also, we cannot write paychecks because we do not know how to pay the employees! Since we only have one class, do the pay the employees a base salary or do we pay them an hourly rate or do pay them a consulting fee? It is impossible to pay the variety of employees using one single class. Therefore it is going to be a lot of work to write the Salary class and the Hourly class and any other employee classes that we need since we have to rewrite every single attribute and method. Right? NO! We can use Inheritance! With Inheritance, we create a base class and then extend this base class into subclasses. In other words, we create a Parent class and then create Child classes that inherit the attributes and behaviors from the Parent class. This way, we only have to write the attributes and behaviors that are unique to that Child class!

Since we are using object-oriented programming techniques, it will be easy to "extend" the base class into many different subclasses. We will only need to code the differences in the Child classes. Once we set up the Inheritance relationship, we can set up our ListBox to automatically show the Child properties by overriding the ToString( ) method. Inheritance is going to save us a massive amount of work!

Steps

1. Open your course project solution from last week. Previously, we created an Employee class to encapsulate the employee information. This week, we are going to create a Benefits class that encapsulates the important benefits information that we want to track for each employee. Now, here is the most important part. Each Employee object must contain a Benefits object. This way, when we have an Employee object open, we can simply open that Employee object's Benefits object. In OOP speak, this is called "Composition". The Employee object is composed of a Benefits object.

Think of it like this. If you have a Person object, you can use the dot operator to get the person's Wallet object. The Person "has a" Wallet, or the Person contains a Wallet. Once the Wallet object is open, we can check important information like drivers license number or amount of cash the person has in their wallet.

If we use Composition, we will create an attribute in our Employee class that is a Benefits object. The Employee object will be composed of a Benefits object. This way, we can open our Employee object. Then, we can use the dot operator on the Employee object to get the Benefits object that it contains.

Create a Benefits class. Then, create an attribute in the Employee class so the Employee class contains a Benefits object. Here is the UML class diagram for the Benefits class showing the Composition relationship between the Employee class and the Benefits class.

Figure 1: see image.

2. Since we changed the structure of our Employee class, we need to update project to accommodate the updated Employee objects.

a. Change your Input form to get the Benefits information as well

Figure 2: see image.

b. Update the AddButton_Click event method to get the additional information and create Employee objects using Composition.

private void AddButton_Click(object sender, EventArgs e)
{
// add item to the employee listbox
InputForm frmInput = new InputForm();

using (frmInput)
{
DialogResult result = frmInput.ShowDialog();

// see if input form was cancelled
if (result == DialogResult.Cancel)
return; // end method since user cancelled the input

// get user's input and create an Employee object
string fName = frmInput.FirstNameTextBox.Text;
string lName = frmInput.LastNameTextBox.Text;
string ssn = frmInput.SSNTextBox.Text;
string date = frmInput.HireDateTextBox.Text;
DateTime hireDate = DateTime.Parse(date);
string healthIns = frmInput.HealthInsTextBox.Text;
double lifeIns = Double.Parse( frmInput.LifeInsTextBox.Text );
int vacation = Int32.Parse( frmInput.VacationTextBox.Text );

Benefits benefits = new Benefits(healthIns, lifeIns, vacation);
Employee emp = new Employee(fName, lName, ssn, hireDate, benefits);

// add the Employee object to the employees listbox
EmployeesListBox.Items.Add(emp);

// write all Employee objects to the file
WriteEmpsToFile();
}
}

c. Update the WriteEmpsToFile( ) method to write all of the Employee information, including the Benefits information:

private void WriteEmpsToFile()
{
// write all Employee objects to the file
string fileName = "Employees.csv";
StreamWriter sw = new StreamWriter(fileName);
for (int i = 0; i < EmployeesListBox.Items.Count; i++)
{
Employee temp = (Employee)EmployeesListBox.Items[i];
sw.WriteLine(temp.FirstName + ',' + temp.LastName + ','
+ temp.SSN + ',' + temp.HireDate.ToShortDateString()
+ ',' + temp.BenefitsPackage.HealthInsurance
+ ',' + temp.BenefitsPackage.LifeInsurance
+ ',' + temp.BenefitsPackage.Vacation);
}

sw.Close();

// tell user that the records were written to the file
MessageBox.Show("Employees were written to the file.");
}

d. Update the ReadEmpsFromFile( ) method to read all of the Employee information, including the Benefits information:

private void ReadEmpsFromFile()
{
// read all Employee objects from the file
string fileName = "Employees.csv";

StreamReader sr = new StreamReader(fileName);
using (sr)
{
while (sr.Peek() > -1)
{
// read the line and break it into parts based on commas
string line = sr.ReadLine();
string[] parts = line.Split(',');

string fName = parts[0];
string lName = parts[1];
string ssn = parts[2];
DateTime hireDate = DateTime.Parse(parts[3]);
string healthIns = parts[4];
double lifeIns = Double.Parse(parts[5]);
int vacation = Int32.Parse(parts[6]);

// create the Employee object and add it to the listbox
Benefits benefits = new Benefits(healthIns, lifeIns, vacation);
Employee emp = new Employee(fName, lName, ssn,
hireDate, benefits);
EmployeesListBox.Items.Add(emp);
}
}
}

3. How can we see the details for our Employee objects? We can set up the double-click event on the listbox!

  • Add the double-click event to the listbox
  • Display the Employee object's information in the InputForm, which we will repurpose as an Update form
  • If the user clicks the Cancel button, end the method
  • If the user clicks the Submit/Update button:
    • Delete the selected Employee object
    • Create a new Employee object using the updated information
    • Add the new Employee object to the listbox

4. Next we will create a Salary class that inherits from the Employee class. This way, we automatically get all of the Employee attributes and behaviors. Add an annualSalary attribute to the Salary class. Set up the constructors to get all of the information, both the parent information and the child information. Pass the parent information to the parent's constructor.

5. Create an Hourly class that inherits from the Employee class. Add an hourlyRate attribute and an hoursWorked attribute. Set up the constructors to get all of the information, the parent information and the child information. Remember to pass the parent information to the parent's constructor!

Here is the UML class diagram showing the Inheritance relationship between the Employee parent class and the Salary and Hourly child classes: see image.

6. Update your Input form to take Hourly employee information and Salary employee information. Use RadioButtons so the user can choose the Employee type. Then, get the appropriate information based on the employee type

Update your methods that read and write to the file to accommodate the child classes. We can use another field ("Type") and then convert the line to the appropriate class type. On the other hand, if we convert our listbox items to a standard list, we can write the entire list to the file with one line of code! Technically, we can write the listbox items directly to the file, but that would cause a maintenance issue in the future. By using a standard list, we can change our form in the future with no issues at all!

Convert the listbox items to a list that can work with Employee objects. We can use a foreach loop to quickly make this conversion. The foreach loop will get each object, one at a time, and apply the code to that object. It will apply your code to each object in the array or collection. In addition, the foreach loop automatically converts the objects to the data type that you give it! Update your WriteEmpsToFile( ) method:

List< Employee > empList = new List< Employee >();

foreach (Employee emp in EmployeesListBox.Items)
{
empList.Add(emp);
}

Now, let's use the BinaryFormatter to write the entire list to the file in one line! Create your pipe to the file. Then, create your BinaryFormatter as our "translator" that can translate you object into binary. Then, write the entire object to the file. Remember to close your pipe!

// convert the listbox items to a generic list
List< Employee > empList = new List< Employee >();

foreach (Employee emp in EmployeesListBox.Items)
{
empList.Add(emp);
}

// open a pipe to the file and create a translator
FileStream fs = new FileStream(FILENAME, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();

// write the generic list to the file
formatter.Serialize(fs, empList);

// close the pipe
fs.Close();

We also need to update your ReadEmpsFromFile( ) method. Check to see if the file exists AND ALSO check to make sure the file has a length greater than zero. If it does, create a file stream from the file. Also, create your BinaryFormatter ("translator"). Read the list into a list reference. Finally, copy the Employee objects into your listbox items.

// check to see if file exists
if( File.Exists(FILENAME) && new FileInfo(FILENAME).Length > 0 )
{
// create a pipe from the file and create the "translator"
FileStream fs = new FileStream(FILENAME, FileMode.Open);
BinaryFormatter formatter = new BinaryFormatter();

// read all Employee objects from the file
List< Employee > list = (List< Employee >)formatter.Deserialize(fs);

// close the pipe
fs.Close();

// copy the Employee objects into our listbox
foreach (Employee emp in list)
EmployeesListBox.Items.Add(emp);
}

On Your Own

Add code for the print paychecks button. It should display in a MessageBox the employee information (hint: use ToString()) and the pay (use CalculatePay()). The result should look like this: see image.

Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.