Woah! Don’t slip! We still have some WET code. Take a second look at EmployeeController
:
public class EmployeeController { Integer currentYear = 2023; Employee jerryEmployee = new Employee('Jerry', 2015); Integer jerryTenure= calculateTenure(jerryEmployee); Employee elaineEmployee = new Employee('Elaine', 2018); Integer elaineTenure = calculateTenure(elaineEmployee); private Integer calculateTenure(Employee emp){ Integer tenure = this.currentYear - emp.startYear; return tenure; } }
The code works fine, sure, but it’s doing too much. EmployeeController
is responsible for creating an Employee
object AND calculating its tenure. Yikes.
Think back to why we created the Employee
class. Our goal was to encapsulate the attributes of an employee. Tenure is one of those attributes, but its calculation leaked onto the EmployeeController
. It’s no longer encapsulated.
If other classes also instantiate employees and need tenure, they’d have to recreate their version of the method.
Let’s refactor for DRYer code by reassigning responsibilities. The solution is to give the Employee
class the responsibility to calculate tenure. If a class like EmployeeController
needs to know the tenure, it should ask the employee object.
To do this, we’ll simply move the method out of EmployeeController
and into Employee
:
public class Employee { String firstName; public Integer startYear {get; private set;} Employee(String firstName, Integer startYear){ firstName = firstName; startYear = startYear; } public Integer calculateTenure(Integer currentYear){ Integer tenure = currentYear - this.startYear; return tenure; } }
We’ve made some slight updates in the process. The method needs to be accessed by other classes, so it’s been marked as public
. The parameters have also been updated. startYear
is within scope because it’s a member variable for this class, but currentYear
is not. So, the caller must provide the current year as an argument.
Now, to call this method from EmployeeController
:
public class EmployeeController { Integer currentYear = 2023; Employee jerryEmployee = new Employee('Jerry', 2015); Integer jerryYearsOfEmployment = jerryEmployee.calculateTenure(currentYear); Employee elaineEmployee = new Employee('Elaine', 2018); Integer elaineYearsOfEmployment = elaineEmployee.calculateTenure(currentYear); }
The Dot Operator
Using the dot operator, we’re able to call the calculateTenure
method defined in the Employee
class and pass in the argument.
The dot operator is a fundamental concept in object-oriented programming. You will need it whenever you want to access another object's properties or invoke its methods. In the statement jerryEmployee.calculateTenure(currentYear)
, the dot operator is saying, "call the calculateTenure method that belongs to the jerryEmployee object and pass in the currentYear variable." It helps you navigate through another object to reach its properties and methods.
The keyword there being another object's properties and methods. If we wanted to call calculateTenure from the Employee constructor, we'd do so like this:
public class Employee { String firstName; public Integer startYear {get; private set;} Employee(String firstName, Integer startYear){ firstName = firstName; startYear = startYear; calculateTenure(2024); } public Integer calculateTenure(Integer currentYear){ Integer tenure = currentYear - this.startYear; return tenure; } }
There's no dot operator here because the method belongs to the same class. We only need the operator when accessing another object's properties or methods.
The ability to call methods using the dot operator is crucial for encapsulation, enabling objects to interact while maintaining their boundaries. More on that in the OOP course.