Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Start a free Basic trial
to watch this video
Typically when we want to share behavior among a closely related group of objects, we use inheritance. This isn't always the right tool for the job though and in this video we take a look at a situation where an inheritance hierarchy can be limiting.
-
0:00
We now know the basic syntax of protocols, but why are they useful?
-
0:04
Let's take a look at a scenario.
-
0:06
Now bear with me, this is going to be a bit of a longer example.
-
0:09
So we'll have more code than usual to write.
-
0:12
Here we're going to define another hypothetical piece of softwar,
-
0:15
an employee database for a particular company.
-
0:18
So what could the employee class look like?
-
0:21
So let's do something like this, import Foundation.
-
0:25
I'm going to define an enum EmployeeType.
-
0:29
This isn't necessary, but it'll make our example a bit cleaner.
-
0:34
So we have managers and traditional.
-
0:37
And then our Employee class
-
0:41
is going to define some basic properties, some basic attributes about an employee.
-
0:47
So we'll have a name, We'll have an address,
-
0:54
A startDate, What type of employee they are,
-
1:00
so EmployeeType, And then we'll have an initializer.
-
1:07
So init with name, address.
-
1:12
We'll just make this easy and
-
1:13
give the exact stored property values through the initializer.
-
1:17
A startDate, And a type.
-
1:24
Okay, self.name = name, self.address = address.
-
1:32
If anything, this is good practice as to how you create an initializer and
-
1:36
set up stored properties.
-
1:39
And then type.
-
1:42
And let's say we're going to use this software to pay our employees.
-
1:46
So we need to implement a method to calculate a particular employee's wages.
-
1:51
Now here's where things can start to get hairy.
-
1:53
In most companies, there are different types of employees.
-
1:57
Let's assume, in our example, we have two types, hourly employees and
-
2:01
salaried employees.
-
2:03
How would we model this?
-
2:05
Now since hourly and salaried employees both have a lot of information in common,
-
2:10
information that we've already modeled in the Employee class,
-
2:13
we can create two classes, hourly employee and
-
2:17
salaried employee, that are subclasses of the Employee class.
-
2:21
So they'd look something like this, class HourlyEmployee.
-
2:28
This inherits from Employee.
-
2:31
And then it adds information about hourlyWage.
-
2:38
And to make this example easier and not have to define initializers,
-
2:42
we'll just give these default values.
-
2:45
hoursWorked, for now we'll just put as 0.
-
2:50
And vacation time.
-
2:55
I don't really need these, so let's get rid of those.
-
3:00
Okay, so this is what HourlyEmployee looks like.
-
3:02
It has everything Employee has plus some additional information about
-
3:07
how long they worked.
-
3:08
What about salaried?
-
3:09
So class SalariedEmployee, Also inherits from Employee.
-
3:16
And then we're going to add some information, again, a default value.
-
3:22
We'll say this is random 50000.00.
-
3:27
Then benefits, These are purely arbitrary.
-
3:37
Deductions, And
-
3:42
some vacation time.
-
3:46
Let's make another assumption about this software while we're at it.
-
3:49
Payroll is handled by a separate component in this app.
-
3:53
When calculating the pay for a particular employee,
-
3:56
a pay method is called on an instance of an employee class.
-
4:01
We don't have a payroll app modeled, of course.
-
4:03
But we can assume it would look something like this.
-
4:06
We would have a pay function that takes an Employee instance.
-
4:13
And then does something with it.
-
4:14
We're going to issue a paycheck by calling some pay method on
-
4:18
each of these employees.
-
4:20
Every time we call pay, regardless of whether it was a salaried employee or
-
4:24
hourly, we expect a certain result back.
-
4:28
Let's say we want information about the base pay, benefits, vacation, and
-
4:32
any deductions.
-
4:33
Now we also need to guarantee that our subclasses contain this
-
4:36
pay method that returns this information.
-
4:38
And that both of them return the same type.
-
4:41
Because we just want to call pay on an Employee.
-
4:44
We don't want to worry about what type of employee this is and so on.
-
4:48
So how do we do this?
-
4:50
One way is we could define the pay method in the base class,
-
4:54
Employee, so that both subclasses inherit it.
-
4:58
So let's try that.
-
4:59
Before we implement a pay function in the Employee class,
-
5:03
let's create a very simple struct to represent a paycheck of sorts.
-
5:07
So struct Paycheck.
-
5:10
And this will have information about the base pay, any benefits,
-
5:17
Any deductions, and vacation time.
-
5:24
So now we can go back to Employee and define a pay function,
-
5:32
That will return a paycheck every time it's called.
-
5:36
Unfortunately, in the Employee class,
-
5:39
we don't have any of the information we need to calculate pay.
-
5:42
So we just need to return placeholder values for now.
-
5:45
So we'll say return Paycheck.
-
5:47
And then using that initializer, it will just pass in 0 for all the values.
-
5:52
Now this is already starting to look bad.
-
5:54
Because we have a method here, pay, that returns incorrect information.
-
5:59
Well, let's ignore that for now.
-
6:01
But now, in pay, when we get an Employee, so when we call the pay method,
-
6:06
we can then go ahead and call that pay function on each employee to pay them.
-
6:10
Okay, but we still don't have any accurate information, right?
-
6:14
If I were to call pay, even if it were an instance of HourlyEmployee or Salaried,
-
6:18
it would revert to calling pay on the base class, which returns 0.
-
6:23
What we need to do is go into each subclass and then override the pay method.
-
6:29
And use specific information that each class provides to calculate wages.
-
6:34
So for example, I can override pay in HourlyEmployee.
-
6:38
I can calculate their base pay by doing the hourlyWage * hoursWorked.
-
6:44
And then I'll return a paycheck instance with the base pay.
-
6:50
And for the sake of the example, 0 for everything else.
-
6:55
So this needs to be 0.0.
-
6:57
Because we have an error since they're incompatible types, okay?
-
7:02
And now this seems to work.
-
7:04
Let's not worry about SalariedEmployee just yet.
-
7:06
But let's look into the future.
-
7:08
The company has grown and hourly employees are further broken down into two
-
7:12
categories, part-time and full-time.
-
7:15
Now we have to override the pay method again in each of these subclasses.
-
7:19
And make sure we're doing the right thing.
-
7:21
This is far from the ideal solution.
-
7:23
By requiring us to override a method to implement the correct functionality,
-
7:27
we've made a room for some bad bugs.
-
7:30
The big thing is what if I forget to override the pay method
-
7:33
in the HourlyEmployee class?
-
7:35
Now if I call pay on an instance, the method in the parent class is executed.
-
7:41
And this returns useless values.
-
7:43
For example, let's assume that I'd forgotten here to implement pay for
-
7:47
the SalariedEmployee.
-
7:48
And if I passed in an instance of the SalariedEmployee to the pay function,
-
7:53
I'm going to get a paycheck of 0.
-
7:56
If this were a real app and this bug goes unnoticed, because we're not doing
-
8:00
anything wrong that the compiler can identify and tell us,
-
8:03
we're going to send out a paycheck of $0 to all our hourly employees.
-
8:07
This is where some facets of inheritance start to breakdown.
-
8:11
In that they're not ideal for all use cases.
-
8:14
Yes, these classes are related in that they're all employees and
-
8:18
we reuse code and encapsulate data here by using inheritance.
-
8:23
But not all aspects of the classes are related.
-
8:26
Mind you, I'm not saying that inheritance is bad.
-
8:29
It just doesn't work here.
-
8:30
It may not be the right tool for this job, specifically.
-
8:33
Protocols, though, offer a different kind of solution.
-
8:36
Let's take a break here.
-
8:37
In the next video, we'll revisit this same problem using protocols.
You need to sign up for Treehouse in order to download course files.
Sign up