Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated:
1
00:00:04,390 --> 00:00:10,910
So the next point I want to dig into is point nine, thou shalt use composition over inheritance.
2
00:00:10,930 --> 00:00:13,660
What does composition and inheritance mean?
3
00:00:13,780 --> 00:00:17,970
Why should we prefer one over the other composition over inheritance?
4
00:00:17,980 --> 00:00:23,050
So a classic example of where inheritance can go wrong is the following.
5
00:00:23,080 --> 00:00:29,710
Imagine we start off with an animal class and that's going to be our super class is going to be what
6
00:00:29,710 --> 00:00:30,820
we inherit from.
7
00:00:30,940 --> 00:00:35,890
If you are not too familiar with inheritance, this is where we take all of the functionality of this
8
00:00:35,890 --> 00:00:36,280
class.
9
00:00:36,370 --> 00:00:39,700
Essentially, we say anything that I inherit from it is one of these.
10
00:00:39,700 --> 00:00:41,530
It has all of that and more.
11
00:00:41,880 --> 00:00:45,790
So a mammal, for example, might be a type of animal.
12
00:00:45,820 --> 00:00:49,440
Not all animals are mammals, but all mammals are animals.
13
00:00:49,450 --> 00:00:53,740
And so a mammal will have all of the functionality of the animal.
14
00:00:53,770 --> 00:00:55,650
It will be an animal.
15
00:00:55,660 --> 00:01:01,870
So if an animal has a live method implemented here, then an animal also has that live method.
16
00:01:01,870 --> 00:01:05,420
It automatically inherits that from the animal class.
17
00:01:05,440 --> 00:01:08,080
The mammal, however, can add its own functionality as well.
18
00:01:08,080 --> 00:01:12,340
As you can see here, the mammal adds on the functionality of being able to make milk, and anything
19
00:01:12,340 --> 00:01:14,570
that inherits from the mammal will be able to make milk.
20
00:01:14,590 --> 00:01:20,680
We might have another subclass of animal, which further specializes in or specialize it differently
21
00:01:20,680 --> 00:01:25,840
to the mammals such as reptile, which allows it to lay eggs that gives it that functionality there.
22
00:01:25,840 --> 00:01:31,300
And then we can actually inherit some actual instances or some actual classes from this that we might
23
00:01:31,300 --> 00:01:34,950
instantiate, such as the cow or a snake from reptile.
24
00:01:34,960 --> 00:01:39,760
And you can see how they're going to get all of the appropriate functionality here.
25
00:01:39,790 --> 00:01:45,700
Cow gets to make milk and live, the snake gets to lay eggs and live, and they share the common functionality
26
00:01:45,700 --> 00:01:49,150
of living, but they get to differentiate functionality as well.
27
00:01:49,180 --> 00:01:54,430
This all seems fine and glorious and really easy up until the point where you find something that doesn't
28
00:01:54,430 --> 00:01:57,130
match your inheritance taxonomy.
29
00:01:57,130 --> 00:02:03,100
So you might find something like a platypus, which suddenly doesn't inherit from mammal very easily
30
00:02:03,100 --> 00:02:04,780
because it wants to be able to lay eggs.
31
00:02:04,780 --> 00:02:08,979
But it doesn't inherit from reptiles because it's warm blooded and it needs to make milk.
32
00:02:09,009 --> 00:02:10,750
So why do we inherit from?
33
00:02:10,759 --> 00:02:13,690
And this is a very common issue with inheritance.
34
00:02:13,690 --> 00:02:16,120
You will find that stuff kind of starts to happen.
35
00:02:16,120 --> 00:02:21,190
You'll find things that you want to inherit from multiple places and languages like C Sharp will not
36
00:02:21,190 --> 00:02:24,910
let you inherit from multiple places because then you wouldn't know.
37
00:02:24,970 --> 00:02:31,180
For example, if I were to call the live method on platypus, do I call it via the mammal side or the
38
00:02:31,180 --> 00:02:31,990
reptile side?
39
00:02:32,010 --> 00:02:33,610
What if the reptile had overridden it?
40
00:02:33,610 --> 00:02:35,170
And so it gets very confusing.
41
00:02:35,170 --> 00:02:38,860
And obviously a platypus isn't really a reptile, but it does have the ability to lay eggs.
42
00:02:39,010 --> 00:02:40,780
This gets very confusing composition.
43
00:02:40,780 --> 00:02:43,150
On the other hand, it can be a lot more powerful.
44
00:02:43,150 --> 00:02:44,800
It can be a lot more verbose as well.
45
00:02:44,800 --> 00:02:49,980
It can mean that we have to write methods that expose the functionality of these components.
46
00:02:49,990 --> 00:02:55,810
It can be a little bit more complicated than inheritance, but it can save us a lot of that kind of
47
00:02:55,810 --> 00:02:56,320
hassle.
48
00:02:56,650 --> 00:03:01,660
So you may be familiar with composition in the sense of unity components.
49
00:03:01,960 --> 00:03:07,960
We can take a GameObject and add all sorts of different components to it to make it behave how we want
50
00:03:07,960 --> 00:03:08,260
it to.
51
00:03:08,290 --> 00:03:12,940
So instead of having a player class, we'd have a player game object and we would give it a movement
52
00:03:12,940 --> 00:03:13,570
component.
53
00:03:13,570 --> 00:03:18,910
We would give it some particle effect components, we'd give it some animate components and that the
54
00:03:18,910 --> 00:03:25,150
combination of those components, the composition of those components gives it its actual functionality
55
00:03:25,150 --> 00:03:27,910
and those components have to coordinate between themselves.
56
00:03:28,000 --> 00:03:30,220
So we could do the same thing with a cow.
57
00:03:30,220 --> 00:03:32,920
And in this case, you could still have a coordinating class.
58
00:03:32,920 --> 00:03:38,980
You could still have a cow class that coordinates and composes a bunch of functionality driven components.
59
00:03:39,160 --> 00:03:41,500
So, for example, we might have a milk making component.
60
00:03:41,500 --> 00:03:43,600
The cow will have a say.
61
00:03:43,600 --> 00:03:45,180
You notice the change in language here.
62
00:03:45,250 --> 00:03:48,930
Inheritance we talk about is a would say the cow is a mammal.
63
00:03:48,940 --> 00:03:55,720
Here, we're saying that the cow has a milk making component and it would need to write some wrapper
64
00:03:55,720 --> 00:04:01,480
functionality to make sure it is calling to that make milk function in the right places and so on and
65
00:04:01,480 --> 00:04:06,100
so forth, but is able to reuse that functionality at will.
66
00:04:06,100 --> 00:04:11,650
And the snake could have an egg laying components and similarly could cool to that functionality.
67
00:04:11,650 --> 00:04:17,829
And now the platypus has got a very easy choice of simply including both being able to have a milk making
68
00:04:17,829 --> 00:04:20,019
component and have an egg laying component.
69
00:04:20,019 --> 00:04:23,860
And composition and inheritance isn't an either or situation.
70
00:04:23,860 --> 00:04:25,780
You could easily have both of these.
71
00:04:25,780 --> 00:04:28,840
You could have that the mammal has a milk making component that you have.
72
00:04:28,840 --> 00:04:34,060
The reptile has an egg laying component, and the platypus is a mammal that also has an egg laying component
73
00:04:34,070 --> 00:04:37,000
so you can start to mix and match these things as well.
74
00:04:37,030 --> 00:04:42,550
But what we're saying here is that try and put more of your heavy functionality into components.
75
00:04:42,550 --> 00:04:44,560
They are far more reusable.
76
00:04:44,560 --> 00:04:49,870
They are far more flexible than trying to stuff all of that functionality into parent classes and an
77
00:04:49,870 --> 00:04:50,500
inheritance.
78
00:04:50,500 --> 00:04:55,210
Try and use the inheritance as little as possible, try and use components as much as possible.
79
00:04:55,390 --> 00:04:57,580
And that's what composition over inheritance means.
80
00:04:57,850 --> 00:05:03,350
It is not a hard and fast rule saying that you must use competition all the time and never use inheritance.
81
00:05:03,400 --> 00:05:06,070
It's saying try to use one more than the other.
82
00:05:06,460 --> 00:05:11,030
So let's have a little challenge to see if you can figure out where this picture goes wrong.
83
00:05:11,110 --> 00:05:16,120
This is an inheritance hierarchy, and what I've listed out is some of the functionality that you might
84
00:05:16,120 --> 00:05:17,590
expect to see in these classes.
85
00:05:17,600 --> 00:05:22,630
So at the top level, we've got a character that has a shared functionality between a player and an
86
00:05:22,630 --> 00:05:23,050
enemy.
87
00:05:23,080 --> 00:05:27,670
It is able to do locomotion, so moving around the world, it's able to attack it.
88
00:05:27,700 --> 00:05:29,740
It has health, these kinds of things.
89
00:05:29,750 --> 00:05:31,930
We want both a player and enemy to have great.
90
00:05:32,140 --> 00:05:35,640
So we inherit in player and enemy from the correct class.
91
00:05:35,650 --> 00:05:39,520
The player adds a layer of player control logic.
92
00:05:39,520 --> 00:05:45,190
It also adds some upgrade ability, such as maybe in an RPG, you are able to level up your character.
93
00:05:45,310 --> 00:05:47,920
The enemy, on the other hand, does not have the upgradability.
94
00:05:47,920 --> 00:05:51,150
Enemies are kind of more fixed and programmed into the level.
95
00:05:51,160 --> 00:05:56,260
However, they do have air control and they are programmed to be hostile to the player when you approach
96
00:05:56,260 --> 00:05:56,470
them.
97
00:05:56,500 --> 00:06:04,300
This seems fine and great, but can you imagine what you might add to this game that would break or
98
00:06:04,330 --> 00:06:08,830
encourage you to have bad inheritance here or mean duplicated code?
99
00:06:08,830 --> 00:06:09,430
Have a pause?
100
00:06:09,430 --> 00:06:09,930
Have a think.
101
00:06:09,930 --> 00:06:16,900
See if you can think of anything, any type of class here that we'd add and wouldn't match in here.
102
00:06:18,140 --> 00:06:24,530
OK, so what I'm thinking is we could be adding in an NPC, for example, an NPC would need some shared
103
00:06:24,560 --> 00:06:25,810
functionality from the character.
104
00:06:25,810 --> 00:06:29,630
It would need the locomotion, it would need to be able to probably wouldn't need to be able to attack.
105
00:06:29,630 --> 00:06:32,370
So it's going to inherit functionality it doesn't need.
106
00:06:32,390 --> 00:06:34,420
So that's something that's not great already.
107
00:06:34,430 --> 00:06:35,860
It's going to inherit a health.
108
00:06:35,870 --> 00:06:37,910
Maybe you don't want to be able to kill the NPCs.
109
00:06:38,210 --> 00:06:40,790
So maybe it shouldn't be inheriting health either.
110
00:06:41,120 --> 00:06:46,100
So you can see how inheritance is already getting as a model without the fact that actually now going
111
00:06:46,100 --> 00:06:50,830
to have some duplicated code because we might want to have air control and share some of that elite
112
00:06:50,840 --> 00:06:54,740
control that the enemies already got, but without the hostility to the player.
113
00:06:54,740 --> 00:06:59,450
So we don't want to inherit NPC from enemy because then it's going to be hostile to the player and somehow
114
00:06:59,450 --> 00:07:01,470
we've got to switch that off, and that's going to be a bit hacky.
115
00:07:01,490 --> 00:07:06,780
It doesn't really make sense that the NPC is an enemy that doesn't make sense from inheritance standpoint.
116
00:07:06,800 --> 00:07:12,620
And one more thing that we can see here is that these classes are violating the principle that a class
117
00:07:12,620 --> 00:07:13,850
should do one thing.
118
00:07:13,880 --> 00:07:16,340
You can see they are managing many different domains.
119
00:07:16,340 --> 00:07:20,300
They're managing locomotion, they're managing combat health.
120
00:07:20,780 --> 00:07:22,470
I control all that sort of thing.
121
00:07:22,490 --> 00:07:26,480
If we split this in two components, it would help on multiple levels.
122
00:07:26,480 --> 00:07:29,810
It would allow us to compose something like an NPC very easily.
123
00:07:29,810 --> 00:07:34,550
We could include locomotion components, but we could exclude health and attacking.
124
00:07:34,550 --> 00:07:39,470
We could include AoE control components but exclude the hostile to the player components, and that
125
00:07:39,470 --> 00:07:40,890
makes a lot more sense.
126
00:07:40,910 --> 00:07:45,560
Now what you can do to get a bit of the best of both worlds and particularly in unity, is to use the
127
00:07:45,560 --> 00:07:50,600
prefab system as a kind of lair of inheritance, which would allow you to say, have a character prefab
128
00:07:50,600 --> 00:07:52,040
and then inherit from that.
129
00:07:52,040 --> 00:07:56,810
And maybe your NPC wouldn't even inherit from character because all you're doing is adding that locomotion
130
00:07:56,810 --> 00:07:57,320
component.
131
00:07:57,320 --> 00:08:03,080
But it allows you to group together some of those common groupings of components and have still a kind
132
00:08:03,080 --> 00:08:05,960
of inheritance structure for when that is useful.
133
00:08:06,050 --> 00:08:11,060
So hopefully you now understand a little bit better why composition is a good idea of why inheritance
134
00:08:11,270 --> 00:08:13,040
sometimes leads us into trouble.
135
00:08:13,280 --> 00:08:18,500
In the next lecture, we're going to be looking in to the rather obscurely named Law of Demand, sir.
14170
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.