1
00:00:00,980 --> 00:00:02,640
The first decorator class that we're going

2
00:00:02,640 --> 00:00:04,800
to implement is a decorator to log all the

3
00:00:04,800 --> 00:00:07,350
calls we make to the weather Service. In

4
00:00:07,350 --> 00:00:08,920
this decorator, we will track each time

5
00:00:08,920 --> 00:00:10,880
the service gets called, what parameters

6
00:00:10,880 --> 00:00:12,550
are getting passed to it, what the

7
00:00:12,550 --> 00:00:15,940
response is, and how long each call took.

8
00:00:15,940 --> 00:00:17,630
Now we could implement that functionality

9
00:00:17,630 --> 00:00:20,220
directly here in our WeatherService class,

10
00:00:20,220 --> 00:00:21,650
but there are a couple of problems with

11
00:00:21,650 --> 00:00:24,340
that. First, if we start adding a bunch of

12
00:00:24,340 --> 00:00:26,620
logging code into this class, it makes the

13
00:00:26,620 --> 00:00:28,450
class harder to read, and it's harder to

14
00:00:28,450 --> 00:00:30,970
tell exactly what it is doing. There's

15
00:00:30,970 --> 00:00:32,740
also the possibility that adding more

16
00:00:32,740 --> 00:00:34,600
logic into this class, we could

17
00:00:34,600 --> 00:00:36,370
accidentally introduce an error into our

18
00:00:36,370 --> 00:00:39,640
WeatherService code. Second, if we put the

19
00:00:39,640 --> 00:00:41,680
logging code in here, we're now having

20
00:00:41,680 --> 00:00:44,250
this one class handle multiple concerns,

21
00:00:44,250 --> 00:00:46,960
both fetching the data and logging. And if

22
00:00:46,960 --> 00:00:48,950
we want to add more concerns later, say

23
00:00:48,950 --> 00:00:51,180
caching, as we'll do in the next clip,

24
00:00:51,180 --> 00:00:53,160
then we're just exacerbating that problem

25
00:00:53,160 --> 00:00:55,240
of not following the Single Responsibility

26
00:00:55,240 --> 00:00:57,960
Principle. So the better approach is to

27
00:00:57,960 --> 00:00:59,480
create a decorator class that is

28
00:00:59,480 --> 00:01:01,530
responsible for logging, and that will

29
00:01:01,530 --> 00:01:03,110
keep each of these classes narrowly

30
00:01:03,110 --> 00:01:05,510
focused on a single concern, so let's do

31
00:01:05,510 --> 00:01:08,470
that. To implement a decorator class, I'll

32
00:01:08,470 --> 00:01:10,435
start by adding a new class in Visual

33
00:01:10,435 --> 00:01:13,160
Studio. So in my WeatherInterface folder,

34
00:01:13,160 --> 00:01:15,520
I'm going to right‑click and say Add and

35
00:01:15,520 --> 00:01:18,240
then Class, and I will call this class

36
00:01:18,240 --> 00:01:20,980
WeatherServiceLoggingDecorator, and there

37
00:01:20,980 --> 00:01:23,640
we go. The reason I am adding this

38
00:01:23,640 --> 00:01:25,120
decorator class here in the

39
00:01:25,120 --> 00:01:26,950
WeatherInterface folder is because I can

40
00:01:26,950 --> 00:01:29,690
apply this decorator class to any

41
00:01:29,690 --> 00:01:30,460
implementation that implements the

42
00:01:30,460 --> 00:01:33,100
IWeatherService interface. Decorators are

43
00:01:33,100 --> 00:01:34,590
based off of the abstraction

44
00:01:34,590 --> 00:01:36,900
IWeatherService, not any particular

45
00:01:36,900 --> 00:01:39,370
concrete implementation. So for that

46
00:01:39,370 --> 00:01:41,270
reason, it makes more sense to define our

47
00:01:41,270 --> 00:01:43,450
decorator classes up here in this folder

48
00:01:43,450 --> 00:01:45,240
next to the interface that they're based

49
00:01:45,240 --> 00:01:47,510
on. So now that we have this class

50
00:01:47,510 --> 00:01:49,420
created, the first requirement of a

51
00:01:49,420 --> 00:01:51,330
decorator is that it needs to implement

52
00:01:51,330 --> 00:01:53,570
the same interface or extend the same base

53
00:01:53,570 --> 00:01:55,120
class as the classes that it will be

54
00:01:55,120 --> 00:01:57,520
decorating. So I'll go ahead and have this

55
00:01:57,520 --> 00:01:59,250
class implement the IWeatherService

56
00:01:59,250 --> 00:02:02,130
interface, and I'll hit Ctrl+period here

57
00:02:02,130 --> 00:02:03,370
to have Visual Studio create the

58
00:02:03,370 --> 00:02:05,520
appropriate methods for me, and there we

59
00:02:05,520 --> 00:02:08,450
go. The second requirement of a decorator

60
00:02:08,450 --> 00:02:10,310
class is that it needs to take an instance

61
00:02:10,310 --> 00:02:12,400
of the class to be decorated, so in this

62
00:02:12,400 --> 00:02:14,930
case an IWeatherService object. And this

63
00:02:14,930 --> 00:02:16,840
is the object that this decorator class is

64
00:02:16,840 --> 00:02:19,520
wrapping around. So I'll create a member

65
00:02:19,520 --> 00:02:23,140
variable here named innerWeatherService,

66
00:02:23,140 --> 00:02:24,840
and then in the constructor for this

67
00:02:24,840 --> 00:02:26,590
class, that's going to need to take an

68
00:02:26,590 --> 00:02:30,000
IWeatherService object as a parameter. So

69
00:02:30,000 --> 00:02:32,290
I'll do that. And then I'll set the member

70
00:02:32,290 --> 00:02:35,420
variable equal to that parameter. Now,

71
00:02:35,420 --> 00:02:37,020
we're also going to need a logger to write

72
00:02:37,020 --> 00:02:38,710
our data out, so let me go ahead and

73
00:02:38,710 --> 00:02:41,640
create a member variable for the logger,

74
00:02:41,640 --> 00:02:44,410
and then I'll also add a parameter to the

75
00:02:44,410 --> 00:02:45,460
constructor so when this object gets

76
00:02:45,460 --> 00:02:47,290
created, we can have an instance of a

77
00:02:47,290 --> 00:02:51,540
logger passed in to us. And there we go.

78
00:02:51,540 --> 00:02:53,140
And now we're ready to implement the two

79
00:02:53,140 --> 00:02:56,670
methods of our decorator class. First, I'm

80
00:02:56,670 --> 00:02:57,800
just going to put in a default

81
00:02:57,800 --> 00:02:59,520
implementation for each of these methods

82
00:02:59,520 --> 00:03:01,180
where the method will just act as a pass

83
00:03:01,180 --> 00:03:03,030
through and call the innerWeatherService

84
00:03:03,030 --> 00:03:06,360
object. And there we go. At this point,

85
00:03:06,360 --> 00:03:08,150
the class actually will compile, and we

86
00:03:08,150 --> 00:03:09,500
could use it to decorate an

87
00:03:09,500 --> 00:03:12,080
IWeatherService object. However, we

88
00:03:12,080 --> 00:03:13,690
haven't added any functionality at this

89
00:03:13,690 --> 00:03:16,250
point. But I bring this up to point out

90
00:03:16,250 --> 00:03:18,130
that with a decorator class you need to

91
00:03:18,130 --> 00:03:20,150
provide at least a default implementation

92
00:03:20,150 --> 00:03:22,260
for every method on the interface or in

93
00:03:22,260 --> 00:03:24,400
the base class, even if it's just a simple

94
00:03:24,400 --> 00:03:26,990
pass through like this. Otherwise, things

95
00:03:26,990 --> 00:03:29,260
aren't going to work. So make sure that

96
00:03:29,260 --> 00:03:31,090
you've at least provided an implementation

97
00:03:31,090 --> 00:03:34,830
for every method, like you see here. Now,

98
00:03:34,830 --> 00:03:36,260
though, let's go ahead and provide our

99
00:03:36,260 --> 00:03:38,250
actual implementations for these methods.

100
00:03:38,250 --> 00:03:39,010
And I'm going to start with the

101
00:03:39,010 --> 00:03:42,270
GetCurrentWeather method. First, we need

102
00:03:42,270 --> 00:03:44,900
to use the .NET Stopwatch class so we can

103
00:03:44,900 --> 00:03:48,720
time how long this method takes. So there

104
00:03:48,720 --> 00:03:50,720
we go. And now this is going to mean that

105
00:03:50,720 --> 00:03:52,540
we need to pull our result out into a

106
00:03:52,540 --> 00:03:55,910
local variable. So I'll do that. And then

107
00:03:55,910 --> 00:03:57,470
I'll return that variable at the end of

108
00:03:57,470 --> 00:04:00,600
the method now. And finally, I'll paste in

109
00:04:00,600 --> 00:04:02,450
a line of code that's going to write all

110
00:04:02,450 --> 00:04:05,680
this information out to the logger. So

111
00:04:05,680 --> 00:04:07,310
there we go, and I'm going to pause here

112
00:04:07,310 --> 00:04:09,100
for a moment because now this method

113
00:04:09,100 --> 00:04:11,110
really provides a good example of what the

114
00:04:11,110 --> 00:04:13,700
decorator pattern is all about. We have

115
00:04:13,700 --> 00:04:16,780
the call to the inner service here on line

116
00:04:16,780 --> 00:04:18,620
25, but you can see that we've added code

117
00:04:18,620 --> 00:04:20,920
both before and after this call, which

118
00:04:20,920 --> 00:04:22,490
gives us the opportunity to insert

119
00:04:22,490 --> 00:04:25,480
additional functionality around that call.

120
00:04:25,480 --> 00:04:27,200
In this case, we're timing how long the

121
00:04:27,200 --> 00:04:29,295
call takes and logging some information,

122
00:04:29,295 --> 00:04:31,540
but we really could do anything here. We

123
00:04:31,540 --> 00:04:33,280
could modify values that are going into

124
00:04:33,280 --> 00:04:34,970
that inner call, we could modify the

125
00:04:34,970 --> 00:04:37,550
response in some way or take some other

126
00:04:37,550 --> 00:04:39,380
action, but this example here gives you a

127
00:04:39,380 --> 00:04:40,850
good idea of what you can do with a

128
00:04:40,850 --> 00:04:42,760
decorator because you get a chance to

129
00:04:42,760 --> 00:04:44,970
intercept and wrap this inner method call

130
00:04:44,970 --> 00:04:47,960
with some additional logic. I'm going to

131
00:04:47,960 --> 00:04:49,910
implement that same functionality down

132
00:04:49,910 --> 00:04:51,980
here on the GetForecast method, but to

133
00:04:51,980 --> 00:04:53,970
save some time I already have that code

134
00:04:53,970 --> 00:04:55,480
queued up on the clipboard, so I'll just

135
00:04:55,480 --> 00:04:58,390
paste that in. And there we go, our first

136
00:04:58,390 --> 00:05:01,450
decorator class is now completed. We still

137
00:05:01,450 --> 00:05:03,070
need to tell our application, though, that

138
00:05:03,070 --> 00:05:05,380
we want to use this decorator. So to do

139
00:05:05,380 --> 00:05:06,500
that I'm going to go over to the

140
00:05:06,500 --> 00:05:10,430
HomeController. And right here at line 27

141
00:05:10,430 --> 00:05:12,650
where we're creating our WeatherService, I

142
00:05:12,650 --> 00:05:14,230
want to change this so that when we new up

143
00:05:14,230 --> 00:05:16,260
the WeatherService, it is wrapped in our

144
00:05:16,260 --> 00:05:18,700
WeatherServiceLoggingDecorator

145
00:05:18,700 --> 00:05:21,690
constructor, so let me do that. And now I

146
00:05:21,690 --> 00:05:23,600
need a logger, so I'll go ahead and create

147
00:05:23,600 --> 00:05:25,090
one of those that I can pass into our

148
00:05:25,090 --> 00:05:28,200
constructor. And there we go. So now we

149
00:05:28,200 --> 00:05:30,020
have our concrete WeatherService wrapped

150
00:05:30,020 --> 00:05:32,360
in our WeatherServiceLoggingDecorator. So

151
00:05:32,360 --> 00:05:34,150
when we call either of those methods on

152
00:05:34,150 --> 00:05:36,230
the IWeatherService interface, we should

153
00:05:36,230 --> 00:05:37,630
see our calls first pass through the

154
00:05:37,630 --> 00:05:39,380
decorator object before they go to the

155
00:05:39,380 --> 00:05:42,120
WeatherService object. And to prove that,

156
00:05:42,120 --> 00:05:43,730
I'm going to come down here to the Index

157
00:05:43,730 --> 00:05:45,700
action method and I'm going to set a

158
00:05:45,700 --> 00:05:48,320
breakpoint. And now I'm going to go ahead

159
00:05:48,320 --> 00:05:51,510
and I'm going to run the application.

160
00:05:51,510 --> 00:05:52,850
Okay, now I've hit the breakpoint in the

161
00:05:52,850 --> 00:05:54,670
Index method, so let's go ahead and step

162
00:05:54,670 --> 00:05:57,250
through this code. And you see now that

163
00:05:57,250 --> 00:05:59,080
when I call the GetCurrentWeather method,

164
00:05:59,080 --> 00:06:02,180
I'm landing first on our decorator object.

165
00:06:02,180 --> 00:06:04,380
I'll keep debugging, and now if I step

166
00:06:04,380 --> 00:06:06,590
into this next GetCurrentWeather method

167
00:06:06,590 --> 00:06:09,250
call, now I'm down into the WeatherService

168
00:06:09,250 --> 00:06:11,360
object, and this is where the actual API

169
00:06:11,360 --> 00:06:14,180
call gets made. And so I've got some

170
00:06:14,180 --> 00:06:16,000
results now, so I'll go ahead and step out

171
00:06:16,000 --> 00:06:18,720
of this method, and I'm back up in the

172
00:06:18,720 --> 00:06:22,670
logging decorator, so I'll keep going. And

173
00:06:22,670 --> 00:06:24,770
now I'm back up in the Index method in the

174
00:06:24,770 --> 00:06:27,940
HomeController, and I'll let this finish.

175
00:06:27,940 --> 00:06:30,500
And there we go. So, as you can see as we

176
00:06:30,500 --> 00:06:32,020
trace through that call, you can get the

177
00:06:32,020 --> 00:06:34,260
feel for this onion‑like layering where

178
00:06:34,260 --> 00:06:35,900
the method call first passes through the

179
00:06:35,900 --> 00:06:37,790
decorator and then gets to the actual

180
00:06:37,790 --> 00:06:40,310
WeatherService object. And this is really

181
00:06:40,310 --> 00:06:42,020
the essence of the decorator pattern,

182
00:06:42,020 --> 00:06:43,640
where that decorator class is going to

183
00:06:43,640 --> 00:06:46,200
wrap around one or more other objects and

184
00:06:46,200 --> 00:06:47,990
allow you to intercept all of the method

185
00:06:47,990 --> 00:06:51,250
calls and process some logic in there. So

186
00:06:51,250 --> 00:06:52,630
now that we've implemented our first

187
00:06:52,630 --> 00:06:58,000
decorator class, let's refine our skills further by building a second decorator.

