Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses trial
to watch this video
Using class composition and interfaces together make for a very useful pattern (common programming technique).
This video doesn't have any notes.
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
We learned earlier that
inheritance allows us to create
0:00
a new type that includes all of
the functionality of another class.
0:03
We can do something
similar using composition.
0:07
The idea of composition is to create
a new type by combining one or
0:10
more other types together.
0:14
Composition is very common in
object-oriented programming.
0:15
The level class, for example,
is composed of many IInvader objects and
0:19
many Tower objects.
0:24
Objects can be passed in at construction
time, or created any time during or
0:25
after the object's creation.
0:30
Let's use composition to create a new type
of invader that behaves like an invader,
0:32
but doesn't directly inherit
from the invader base class.
0:37
We can accomplish this by
implementing the IInvader interface.
0:40
We'll call this new type of
invader a resurrecting invader.
0:45
So I'll create a new file and
0:48
name it ResurrectingInvader.cs.
0:52
And in the namespace
TreehouseDefense We'll
0:56
create a new class ResurrectingInvader,
1:04
and it will implement
the IInvader interface.
1:09
So this invader, once it's destroyed,
will resurrect into a stronger,
1:14
more fearsome invader.
1:19
We'll have its first incarnation
be a basic invader, and
1:21
we'll make that a private field.
1:24
So I'll say private BasicInvader,
and I'll name this _incarnation1;.
1:25
And the second incarnation
will be a StrongInvader.
1:34
Just like other types of invaders,
1:44
it will also take a path
parameter in its constructor.
1:46
But it won't forward
this to the base class,
1:50
because there is actually no base
class to this ResurrectingInvader.
1:52
Remember, IInvader isn't a class,
it's an interface.
1:56
Instead, in the constructor we'll create
the two invaders that compose our class.
2:01
So we'll say _incarnation1 = new
BasicInvader and pass it the path.
2:07
And we'll do the same
thing with _incarnation2,
2:18
except it's a StrongInvader.
2:21
There we go.
2:26
Because ResurrectingInvader implements the
IInvader interface, we must implement all
2:27
of the members of the interface
in ResurrectingInvader as well.
2:32
So we'll go to the IInvader interface and
we'll copy the member declarations,
2:36
And we'll paste them here.
2:45
IInvader inherits from IMovable and
IMappable, so
2:50
we'll also need to copy the Move
method and the Location property.
2:54
You may have noticed that I like to put
my properties above the constructor and
3:08
I put my methods below it.
3:13
All members in an interface
must be public, so
3:15
we need to make them all public now.
3:18
Now it's just a matter of implementing
each of these members one by one.
3:29
The Location will be the location
of the second incarnation,
3:33
if the first incarnation
has been neutralized.
3:36
Otherwise, it will be the location
of the first incarnation.
3:39
We can use a ternary if statement
to put this all in one line.
3:42
So we'll say Location =>
3:45
_incarnation1.Is neutralized.
3:49
So if it's neutralized,
it will return _incarnation
3:57
2.location, otherwise,
4:04
it'll return _incarnation1.location.
4:08
HasScored will return true if
either incarnation has scored.
4:18
So we'll say HasScored returns
4:23
_incarnation1.HasScored or
4:28
_incarnation2.HasScored.
4:33
Health will return the health of
the non neutralized incarnation,
4:38
just like we did with Location.
4:42
We can just copy this from
Location up here, And
4:44
we'll say so
if _incarnation1 is neutralized,
4:50
then we'll return _incarnation2's Health.
4:55
Otherwise, we'll return
_incarnation1's Health.
4:59
IsNeutralized will return true if both of
the incarnations have been neutralized.
5:05
And IsActive will return true if
the invader is neither neutralized,
5:19
nor has it scored.
5:24
When the Move method is called, both
incarnations will be moved down the path.
5:28
This way, if _incarnation1 is neutralized,
5:33
then _incarnation2 will just pick
up where _incarnation1 left off.
5:36
DecreaseHealth will decrease the health
of _incarnation1 if it hasn't been
5:41
neutralized yet.
5:45
Otherwise, the health of
_incarnation2 will be decreased.
5:46
We'll say if !_incarnation1.IsNeutralized.
5:51
So if _incarnation1 is not neutralized,
5:58
Then _incarnation1.DecreaseHealth.
6:03
And we'll pass it the factor.
6:10
Otherwise, _incarnation2.DecreaseHealth.
6:15
So it could have written the code for
this class half a dozen different ways.
6:26
For example,
6:30
we could have set _incarnation1 to null
when it was neutralized, or we could have
6:31
had a third IInvader variable to keep
track of which incarnation was alive.
6:35
For the users of this class,
6:40
all that matters is that
the interface is implemented.
6:42
As you can see, abstraction and
encapsulation go hand in hand.
6:45
By relying on interfaces,
6:49
we're given the most freedom possible
to implement the class as we see fit.
6:51
Notice that we aren't inheriting
from the IInvader base class,
6:55
we're using composition instead.
6:59
This is a good example of where we can
use composition instead of inheritance.
7:01
In fact, most developers
prefer to use composition and
7:06
implement the interface,
instead of inheriting from a base class.
7:10
This gives us the most flexibility to
alter the class in the future, and
7:14
it removes the dependency
on the base class.
7:18
In general, we want to minimize the amount
of code that our code is dependent on.
7:21
Interfaces allow us to be
dependent on the interface,
7:25
instead of the concrete
implementation of classes.
7:29
That's the beauty of abstraction at work.
7:32
Let's add a resurrecting invader to
one of the invaders in our level.
7:35
This is becoming quite a difficult level
with all these advanced types of invaders.
7:49
We've also got some code here for
7:54
testing the IsOnPath method
that we can remove now.
7:55
Let's compile to make sure nothing broke.
8:01
Hm, we've gotten a few compilation errors.
8:09
Let's see if we can resolve them.
8:11
Let's go back to
ResurrectingInvader here and
8:13
line 16, we forgot our =>.
8:18
Compile again, hmm we've got
another compilation error here.
8:22
This says cannot implicitly convert type
8:28
'TreehouseDefense.ResurrectingInvader' to
'TreehouseDefense.Invader'.
8:30
Hmm, I think I know what's going on here.
8:36
Over here in the game class,
8:39
ResurrectingInvader is
not a type of invader.
8:41
Remember, it doesn't inherit from invader,
it implements the IInvader interface.
8:46
Because each of these other invaders
also implements the IInvader interface
8:53
through the invader class,
we can just change this to IInvader.
8:57
Looks like that fixed it.
9:05
You need to sign up for Treehouse in order to download course files.
Sign upYou need to sign up for Treehouse in order to set up Workspace
Sign up