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
Protocols can be used to model object relationships in situations where inheritance is too rigid or just not right for the job. In this video, we look at a trivial example of an employee payroll app and how we can use protocols to simplify functionality and behavior.
-
0:00
Every subclass of employee needs to have a pay method.
-
0:04
This method also has to have a very specific return value.
-
0:09
We need to centrally enforce this design and we can do that using a protocol.
-
0:14
Let's define the protocol.
-
0:15
Earlier, when we define our first protocol, full nameable,
-
0:19
we specified that conforming types were required to implement a stored property.
-
0:24
With protocols,
-
0:25
we can require specific methods be implemented by conforming types as well.
-
0:30
These methods are written as part of the protocol's definition, in exactly
-
0:35
the same way as for normal methods but without curly braces or a method body.
-
0:41
So over here up at the top above paycheck,
-
0:46
let's define this protocol which will call payable and
-
0:51
define a single instance method requirement.
-
0:54
So we'll say then conforming types need to implement a function
-
0:59
named pay that takes no parameters, and returns a paycheck.
-
1:04
Now we can get rid of the method, the pay method, in our employee base class.
-
1:10
Since employee has no information to calculate pay,
-
1:13
we have a better encapsulation of data and behavior without that particular method.
-
1:18
It doesn't really serve a purpose in there.
-
1:20
Getting rid of this method introduces errors.
-
1:23
And that's because now in our only employee.
-
1:25
We're not overriding a method from our superclass.
-
1:28
So let's get rid of this entire method.
-
1:32
Now, to ensure that our classes always implement the pay method.
-
1:36
All we need to do is conform to the protocol.
-
1:40
Typically, we specify a protocol conformance by adding a colon to the types
-
1:44
name, and then listing the protocol.
-
1:47
But here we've already listed employee as the superclass.
-
1:51
Now to add any additional conformance, all we need to do is add a comma,
-
1:55
and then list the payable protocol as well.
-
1:59
In this way we can specify there are classes conform to multiple protocols.
-
2:03
But let's not get ahead of ourselves.
-
2:06
And this brings up at error and that's because hourly employee now
-
2:09
does not implement pay as required by the protocol.
-
2:13
So let's put that in there.
-
2:14
This is essentially the same as before.
-
2:16
So we type pay.
-
2:18
And it should auto complete because it knows that our type
-
2:20
is missing the pay method.
-
2:22
On the protocol conformance that we've listed in here again will calculate
-
2:28
base as the hours worked times the hourly wage.
-
2:33
And then will return an instance of pay check with the base pay and
-
2:39
then everything else set to zero.
-
2:41
Now we fulfilled our contract and can guarantee that we're implementing pain.
-
2:47
What about salaried employee though because a protocol states that
-
2:51
all you do is implement a method and doesn't care about the body of the method,
-
2:55
here we can provide a different implementation.
-
2:58
So again let's make salaried employee conform to payable and in
-
3:05
here will provide a completely different implementation for the pay method.
-
3:10
We'll say let monthly salary equal salary divided by 12.
-
3:17
And then we'll return paycheck with the base set to monthly.
-
3:24
And then we'll just pass through all the other values from the store properties.
-
3:31
Now we can call pay on either the salaried employee or
-
3:35
hourly employee and get an implementation that makes sense for each type.
-
3:39
Because protocols are fully fledged types like a class or
-
3:43
struct We can go and take this step further.
-
3:47
Now before we move on,
-
3:49
let's fix this error this is supposed to be a double val so that's 2.0.
-
3:54
Now because protocols are fully fledged types something we haven't discussed yet
-
3:58
but we will, like a class or struct they're a fully fledged type.
-
4:03
And because of that we can specify payable as the argument for
-
4:08
a function instead of employee over here.
-
4:11
So the problem now, you'll see,is that employee doesn't have a pay method.
-
4:15
Well, to make this easier we know that SalariedEmployee has a pay method.
-
4:18
So we could say SalariedEmployee and now we can call pay.
-
4:22
But what if we wanted to pass in an hourly employee here.
-
4:25
The nice thing is because peer is a type
-
4:29
we can specify the type of employee here is payable.
-
4:33
This guarantees that we can only pass in an instance of a class or
-
4:38
a time that conforms to the payable protocol.
-
4:41
This can be a bit tricky to understand at first.
-
4:44
You were saying that the instance passed in as an argument to pay
-
4:48
needs to conform to the payable protocol.
-
4:51
The instance can be of type hourly employee,
-
4:54
it can be salaried employee because both of them conform to payable.
-
4:58
But it also means that it can be any type that we create in the future
-
5:02
that conforms to payable.
-
5:04
We don't know anything about these types that are passed in, but
-
5:08
because the interface the blueprint that is exposed to us
-
5:12
tells us that they implement the pay method that's all we care about.
-
5:16
So all we want to do is call pay on each employee payable exposes that.
-
5:22
So what I mean makes poses?
-
5:24
If I create an instance of employee.
-
5:28
Let's say we make a base class right.
-
5:32
Employee and we'll provide some values so we'll say Pasan,
-
5:37
someAddress, The current date and I'm a traditionalEmployee.
-
5:44
And then if I tried to call pay and
-
5:47
pass through the employee this is not going to work.
-
5:51
Because employee the base class does not conform to the payable protocol and
-
5:56
you'll see that here.
-
5:59
Now this way you can see that we're guaranteed that will never call pay
-
6:02
on a class that doesn't implement it.
-
6:04
And because we can do that we don't have to have some
-
6:07
meaningless pay function in the base class that provides bogus values.
-
6:12
Now what if we were to change this from employee to salaried employee?
-
6:18
We can use that same initializer because it inherits it
-
6:21
you'll see that now it works.
-
6:22
So the interesting thing,
-
6:24
what I meant by exposed earlier is because when we pass in this instance through
-
6:29
all we know inside the function is that this employee conforms to payable.
-
6:35
This means that we can only call things that are listed in the payable protocol.
-
6:41
Now we know that we're passing in a salaried employee here.
-
6:44
And salaried employee has a name store property.
-
6:48
But inside here if I were to call employee.name, you'll see that it doesn't
-
6:52
know how to complete because, in the scope of this function, that doesn't exist.
-
6:56
The protocol is a blueprint.
-
6:58
And this blueprint says that all you know about this type is that it implements pay.
-
7:04
You'll get used to this and we'll talk more about this.
-
7:06
But to conclude this example, you'll see that if I change this to HourlyEmployee,
-
7:11
this works again as well because.
-
7:14
Oops, if I spell things right.
-
7:16
Hourly.
-
7:17
Because this type also conforms to payable.
-
7:20
By using protocols, we get the behavior we desire.
-
7:24
Without a lot of the tight fragile coupling
-
7:27
that was achieved by attempting this specific design through inheritance.
-
7:31
This type of structure where we designed a class through protocol conformance rather
-
7:36
than inheritance is called composition and is an extremely powerful tool
-
7:41
that helps build encapsulated loosely coupled models and code bases.
-
7:46
So this was point number one as to why protocols are useful.
-
7:50
When we have a set of closely related classes that implement methods
-
7:54
which define similar behavior but
-
7:56
have different implementations protocols lead to better code than inheritance.
-
8:02
So let me repeat that again.
-
8:03
When we have a set of closely related classes, as these two hour early and
-
8:08
salaried employee classes are, that implements methods which define
-
8:12
similar behavior, which in our case is the pay method, but
-
8:16
end up having different implementations, protocols lead to better code.
-
8:21
Because then we do not have to define
-
8:24
some placeholder type in the base class employee to get to work.
-
8:29
Now earlier we talked about how we could specify payable
-
8:32
as an argument to this function.
-
8:34
This is because in Swift protocols are also first class types on their own.
-
8:38
And in the next video will look a bit more at how this works.
You need to sign up for Treehouse in order to download course files.
Sign up