1
00:00:01,060 --> 00:00:03,390
Let's make this a little more tangible.

2
00:00:03,390 --> 00:00:06,060
The proof is in the pudding, so let's see

3
00:00:06,060 --> 00:00:09,600
null objects in action in real code. What

4
00:00:09,600 --> 00:00:13,030
we have here is an emulation of a typical

5
00:00:13,030 --> 00:00:15,810
MVC style pattern that you might see in a

6
00:00:15,810 --> 00:00:18,720
website. In our case, however, the views

7
00:00:18,720 --> 00:00:20,580
are not going to create web pages. They're

8
00:00:20,580 --> 00:00:23,100
just going to print straight out to the

9
00:00:23,100 --> 00:00:26,630
command line. Also, our scenario is simply

10
00:00:26,630 --> 00:00:29,920
that we have a learner browsing the

11
00:00:29,920 --> 00:00:32,530
Pluralsight website, and we want to get

12
00:00:32,530 --> 00:00:34,840
information about that learner so we can

13
00:00:34,840 --> 00:00:37,920
render information about them in the top

14
00:00:37,920 --> 00:00:40,320
right‑hand corner where one would normally

15
00:00:40,320 --> 00:00:42,250
click to get more information about their

16
00:00:42,250 --> 00:00:45,420
account. We start by instantiating a

17
00:00:45,420 --> 00:00:47,600
LearnerService, and then on that

18
00:00:47,600 --> 00:00:51,040
LearnerService we call GetCurrentLearner.

19
00:00:51,040 --> 00:00:53,690
We take that learner, pass it into our

20
00:00:53,690 --> 00:00:56,370
LernerView, and then ask that view to

21
00:00:56,370 --> 00:00:59,140
render. It's that simple. Let's go ahead

22
00:00:59,140 --> 00:01:02,590
and run it just to see what happens. Well,

23
00:01:02,590 --> 00:01:04,940
it ran really quickly, and we see that the

24
00:01:04,940 --> 00:01:08,010
User Name is David and the Courses

25
00:01:08,010 --> 00:01:11,660
Completed is 83. Now, how did all that

26
00:01:11,660 --> 00:01:14,620
come together? Let's first come up and

27
00:01:14,620 --> 00:01:18,990
look at what a learner is. Notice that

28
00:01:18,990 --> 00:01:21,840
this Learner type is implementing the

29
00:01:21,840 --> 00:01:25,130
ILearner interface. It does have a

30
00:01:25,130 --> 00:01:28,055
constructor, which takes an Id, UserName,

31
00:01:28,055 --> 00:01:30,390
and the number of courses this particular

32
00:01:30,390 --> 00:01:32,930
user has completed, and it makes those

33
00:01:32,930 --> 00:01:35,410
available via properties on the class.

34
00:01:35,410 --> 00:01:39,200
Let's have a look at the LearnerView.

35
00:01:39,200 --> 00:01:42,490
Remember that the LearnerView takes as its

36
00:01:42,490 --> 00:01:45,870
constructor argument a learner. And what's

37
00:01:45,870 --> 00:01:47,940
it going to do? Of course, we're going to

38
00:01:47,940 --> 00:01:51,080
check right away for nulls. We're going to

39
00:01:51,080 --> 00:01:54,830
check if the learner herself is null or if

40
00:01:54,830 --> 00:01:58,060
her username is null. Wouldn't it be great

41
00:01:58,060 --> 00:02:00,680
if we didn't have to do that? Finally,

42
00:02:00,680 --> 00:02:03,150
let's look at the LearnerService. The

43
00:02:03,150 --> 00:02:05,750
LearnerService has some comments that I'm

44
00:02:05,750 --> 00:02:08,230
using to represent code that would

45
00:02:08,230 --> 00:02:11,360
normally go out maybe to a JWT token and

46
00:02:11,360 --> 00:02:14,880
look a claim that has the user ID in it or

47
00:02:14,880 --> 00:02:18,280
by some other means look up the ID of the

48
00:02:18,280 --> 00:02:21,260
learner. In our case right now, the

49
00:02:21,260 --> 00:02:24,620
learnerId is 1. And that was David, as we

50
00:02:24,620 --> 00:02:26,320
saw earlier down at the bottom of the

51
00:02:26,320 --> 00:02:29,370
screen when we ran our code. The learner

52
00:02:29,370 --> 00:02:32,440
is calling GetLearner with the ID number

53
00:02:32,440 --> 00:02:35,890
from a repository. If that learner is

54
00:02:35,890 --> 00:02:38,210
null, it throws a NullReferenceException.

55
00:02:38,210 --> 00:02:40,070
So we've got three places in our code

56
00:02:40,070 --> 00:02:40,810
where we're throwing

57
00:02:40,810 --> 00:02:43,290
NullReferenceExceptions, and rightly so

58
00:02:43,290 --> 00:02:45,940
using our standard programming models.

59
00:02:45,940 --> 00:02:48,570
Let's go ahead and close this and look at

60
00:02:48,570 --> 00:02:52,270
our repo. Our repo is simply an internal

61
00:02:52,270 --> 00:02:56,210
class that builds up some learners in

62
00:02:56,210 --> 00:02:59,920
memory and allows us to retrieve them by

63
00:02:59,920 --> 00:03:02,870
passing in the right ID. If a learner

64
00:03:02,870 --> 00:03:05,380
exists, then we're going to return that

65
00:03:05,380 --> 00:03:08,410
learner. If that learner does not exist,

66
00:03:08,410 --> 00:03:12,230
your repository call returns null. Now,

67
00:03:12,230 --> 00:03:14,550
what happens when we change our learnerId

68
00:03:14,550 --> 00:03:19,540
to 2? Let's run that, and we can see that

69
00:03:19,540 --> 00:03:23,220
Julie has completed 72 courses. If the ID

70
00:03:23,220 --> 00:03:27,660
is 3, we're going to see that Scott has

71
00:03:27,660 --> 00:03:32,240
created 92 courses. But what if we've just

72
00:03:32,240 --> 00:03:34,540
got someone browsing the site who's not

73
00:03:34,540 --> 00:03:37,855
yet logged in? The lookup for the ID

74
00:03:37,855 --> 00:03:41,630
might, in this case, return a ‑1. And when

75
00:03:41,630 --> 00:03:44,480
we run with that ‑1, we're going to get a

76
00:03:44,480 --> 00:03:46,920
NullReferenceException, as one would

77
00:03:46,920 --> 00:03:50,200
imagine. So we can see that on our

78
00:03:50,200 --> 00:03:53,770
LearnerService class right here where the

79
00:03:53,770 --> 00:03:56,430
exception is being thrown. So what might

80
00:03:56,430 --> 00:03:59,780
we do instead? Well, what if we had a null

81
00:03:59,780 --> 00:04:03,390
object to return instead of throwing that

82
00:04:03,390 --> 00:04:06,140
NullReferenceException? Let's create one.

83
00:04:06,140 --> 00:04:08,030
Let's come up here to our ILearner

84
00:04:08,030 --> 00:04:10,410
interface and implement that interface

85
00:04:10,410 --> 00:04:12,850
with a new derived type that we'll refer

86
00:04:12,850 --> 00:04:15,640
to as NullLearner, which is a standard

87
00:04:15,640 --> 00:04:18,670
convention for this pattern. We can then

88
00:04:18,670 --> 00:04:21,490
come over to ILerner and implement the

89
00:04:21,490 --> 00:04:25,420
missing members. We'll take all of them

90
00:04:25,420 --> 00:04:28,600
for our ID. Of course, we're going to

91
00:04:28,600 --> 00:04:32,320
always return ‑1. For UserName, we're

92
00:04:32,320 --> 00:04:34,380
going to return something very

93
00:04:34,380 --> 00:04:42,510
identifiable. Let's call it Just Browsing.

94
00:04:42,510 --> 00:04:45,580
And then finally, for CoursesCompleted,

95
00:04:45,580 --> 00:04:47,990
since we don't know who this is, of

96
00:04:47,990 --> 00:04:51,940
course, the answer here is 0. Let's take

97
00:04:51,940 --> 00:04:57,420
our NullLearner class and move it to its

98
00:04:57,420 --> 00:05:02,050
own file. By convention, perfect. Now

99
00:05:02,050 --> 00:05:03,890
let's head back over to our

100
00:05:03,890 --> 00:05:07,300
LearnerService, and instead of throwing

101
00:05:07,300 --> 00:05:11,690
this null exception, we can return an

102
00:05:11,690 --> 00:05:16,880
instance of our new NullLearner type. And

103
00:05:16,880 --> 00:05:19,520
in theory, we'll be able to go over to our

104
00:05:19,520 --> 00:05:22,160
LearnerView, which receives this learner

105
00:05:22,160 --> 00:05:27,010
and take out the null checks. Let's see

106
00:05:27,010 --> 00:05:30,140
what happens when we run this code. We can

107
00:05:30,140 --> 00:05:32,940
see down below that the User Name is Just

108
00:05:32,940 --> 00:05:35,620
Browsing and Courses Completed is 0. This

109
00:05:35,620 --> 00:05:37,860
means that we got our null object back by

110
00:05:37,860 --> 00:05:41,290
default from our LearnerService. This is a

111
00:05:41,290 --> 00:05:44,790
very simple and standard implementation of

112
00:05:44,790 --> 00:05:47,640
a null object pattern. And you may be able

113
00:05:47,640 --> 00:05:50,600
to see by this time why I tend to think of

114
00:05:50,600 --> 00:05:54,700
this as a default object pattern. But

115
00:05:54,700 --> 00:05:57,500
again, nevertheless, null object pattern

116
00:05:57,500 --> 00:06:04,000
is the name, and people will know what you're talking about when you use it.

