Problem overview
A company pays every employee a salary. A manager is an employee too, but earns a bonus on top. The task is to write two classes so that Manager reuses everything Employee has and changes only how its pay is worked out.
Employee(name, salary)keeps both privately.pay()returns the salary, anddescribe()returns the text<name> earns <pay>.Manager(name, salary, bonus)inherits fromEmployeeand stores the bonus privately. Itspay()returns the parent's pay plus the bonus. It does not writedescribe()again.
Ana, an employee with salary 3000, is described as Ana earns 3000. Bob, a manager with salary 4000 and bonus 1000, is described as Bob earns 5000.
Approach: override one method, inherit the rest
The only thing that differs between the two is the pay. So Manager overrides pay() and inherits everything else. describe() is written once in Employee, and it builds its text from pay(), not from the salary field. When it runs on a manager, the call to pay() goes to the manager's version, so the bonus shows up without a second describe.
In the manager's pay(), the salary is private to Employee, so the manager can't read it. It asks the parent instead, with super.pay(), which runs Employee's version. That way the salary rule stays in the code that owns it.
Step by step
- Employee's
payreturnssalary. The header'sprivate valalready madenameandsalaryprivate fields. - Employee's
describereturns ans"..."string:$name, thenearns, then${pay()}. Callingpay()rather than readingsalaryis what makes the text right for managers. - Manager's
payoverrides the parent's and returnssuper.pay() + bonus. The headerextends Employee(name, salary)hands the name and salary to the parent's constructor, andprivate val bonuskeeps the bonus.
The solution in Scala
class Employee(private val name: String, private val salary: Int) {
def pay(): Int = {
return salary
}
def describe(): String = {
return s"$name earns ${pay()}"
}
}
class Manager(name: String, salary: Int, private val bonus: Int) extends Employee(name, salary) {
override def pay(): Int = {
return super.pay() + bonus
}
}
Scala details:
extends Employee(name, salary)calls the parent's constructor. InManager's header,nameandsalaryhave noval, so they are only parameters passed up, not new fields.overrideis required. A method that replaces an inherited one must be markedoverride, which also lets the compiler catch a misspelled name.super.pay()calls the parent's version. Writing plainpay()in the manager would call the manager's own method again and again, until the program fails with a stack overflow.- String interpolation. In
s"$name earns ${pay()}",$nameinserts a value and${...}inserts the value of any expression, here a method call.
Using the classes
val e = new Employee("Ana", 3000)
val mg = new Manager("Bob", 4000, 1000)
println(e.describe())
println(mg.describe())
println(mg.pay())
val staff: List[Employee] = List(e, mg, new Manager("Cleo", 5000, 0))
for (s <- staff) println(s.describe())
It prints:
Ana earns 3000
Bob earns 5000
5000
Ana earns 3000
Bob earns 5000
Cleo earns 5000
A Manager can be used wherever an Employee is expected. The list is typed List[Employee] and holds both kinds, and each element's describe() uses its own pay(). Cleo, whose bonus is 0, earns exactly her salary.
Complexity
Each method does a constant amount of work: one addition, or building a short string. Both are O(1) in the sizes of the numbers involved.
Common mistakes
- Calling
pay()insidepay(). It recurses forever. Usesuper.pay(). - Reading
salaryindescribe. Managers would be described without their bonus. - Writing
describe()again inManager. It isn't needed, and a copy can drift out of step with the original. - Adding
valto the manager'snameandsalaryparameters. That declares new fields that hide the parent's private ones and duplicate them. - Leaving out
override. The compiler rejects the method.
