1 00:00:06,420 --> 00:00:06,820 Hello. 2 00:00:08,430 --> 00:00:16,350 In this lecture, we're going to talk about Question 39, what is the dependency injection design pattern? 3 00:00:16,980 --> 00:00:22,380 Dependency injection means providing the object that some cross needs. 4 00:00:22,740 --> 00:00:28,980 So its dependencies from the outside instead of having it construct them itself. 5 00:00:29,520 --> 00:00:31,230 Let's see this in practice. 6 00:00:31,530 --> 00:00:37,140 First, let's take a look at the cross that does not use the dependency injection. 7 00:00:37,920 --> 00:00:45,870 The personal data formatter needs to use longer and people data trigger it means they are its dependencies 8 00:00:46,260 --> 00:00:47,250 in this code. 9 00:00:47,430 --> 00:00:55,020 The Personal Data Formatter creates the logger and the people data reader object itself using the new 10 00:00:55,020 --> 00:00:55,830 operator. 11 00:00:56,400 --> 00:00:59,250 They are a couple of issues with this design. 12 00:00:59,640 --> 00:01:06,580 First of all, personal data formatter depends on a very particular implementation of people's data 13 00:01:06,580 --> 00:01:07,650 reading logic. 14 00:01:07,950 --> 00:01:10,800 What if we wanted to use a different data source? 15 00:01:11,070 --> 00:01:17,940 We would not have any way of doing this, as this class commits to using the specific people data reader 16 00:01:17,970 --> 00:01:21,240 object by creating it with the new operator. 17 00:01:21,720 --> 00:01:28,620 Now, those two classes are tightly coupled, and this is particularly problematic when we want to. 18 00:01:28,620 --> 00:01:30,120 You need to test this code. 19 00:01:30,450 --> 00:01:37,380 Let's assume that the people data trigger connects to a real database and sources people information 20 00:01:37,380 --> 00:01:38,100 from there. 21 00:01:38,550 --> 00:01:45,690 If we created the personal data formatter in this fixture, it would instantiate the people data reader, 22 00:01:45,750 --> 00:01:48,090 which would try to access the database. 23 00:01:48,540 --> 00:01:51,120 This is not acceptable in unit tests. 24 00:01:51,600 --> 00:01:57,310 We must have a way of providing a mock implementation instead of the current design. 25 00:01:57,330 --> 00:01:58,440 It's not possible. 26 00:01:58,800 --> 00:02:02,310 We'll learn more about MOCS later in the course. 27 00:02:02,880 --> 00:02:06,970 Lastly, we are breaking the single responsibility principle here. 28 00:02:07,470 --> 00:02:15,090 The personal data formatter should only be responsible for formatting personal data, but now it is 29 00:02:15,090 --> 00:02:20,350 also responsible for creating the logo and the people they carry their objects. 30 00:02:20,880 --> 00:02:24,390 In this simple code, this may not seem like an issue. 31 00:02:24,540 --> 00:02:31,350 Let's keep in mind that in real life applications is often much more complicated to create an object, 32 00:02:31,560 --> 00:02:34,440 as it may have many dependencies of its own. 33 00:02:35,610 --> 00:02:39,090 Let's refactor this code to use dependency injection. 34 00:02:39,480 --> 00:02:44,370 First of all, let's make the people data reader implement an interface. 35 00:02:53,940 --> 00:03:01,380 And now let's inject this dependency to the personal data for Masterclass instead of creating it right 36 00:03:01,380 --> 00:03:01,770 in a. 37 00:03:24,760 --> 00:03:25,470 All right. 38 00:03:25,960 --> 00:03:32,860 As you can see now, the personal data formatter is given the objects implementing the interfaces it 39 00:03:32,860 --> 00:03:35,890 needs instead of creating them itself. 40 00:03:36,580 --> 00:03:42,580 This solves all problems mentioned before the glasses are now loosely coupled. 41 00:03:42,970 --> 00:03:45,010 We can easily switch the objects. 42 00:03:45,010 --> 00:03:52,030 We passed to the personal data for constructor, to any other objects implementing a logger and old 43 00:03:52,030 --> 00:03:53,980 people data reader interfaces. 44 00:03:54,460 --> 00:03:57,190 If we need, we can also do it at runtime. 45 00:03:57,760 --> 00:04:03,760 Personal Data Formatter doesn't know anything about the concrete people data we get across. 46 00:04:04,180 --> 00:04:10,100 All it cares about is that it's being provided a dependency that can retrieve people's data. 47 00:04:10,570 --> 00:04:16,570 It doesn't care how it's done exactly when we would be creating unit tests for this class. 48 00:04:16,810 --> 00:04:23,470 We could easily provide a mock of the old people data reader interface to avoid connecting to our real 49 00:04:23,470 --> 00:04:24,260 database. 50 00:04:24,790 --> 00:04:31,720 The Personal Data Formatter is no longer responsible for creating the logger and the people data reader 51 00:04:31,720 --> 00:04:32,530 objects. 52 00:04:32,980 --> 00:04:37,450 The creation of those objects and using them are separated. 53 00:04:37,840 --> 00:04:44,050 The single responsibility principle is not broken, and we maintain the separation of concerns. 54 00:04:44,710 --> 00:04:49,060 As you can see, the dependency injection is a straightforward pattern. 55 00:04:49,180 --> 00:04:51,310 It it solves a lot of problems. 56 00:04:51,670 --> 00:04:58,750 In C-sharp, we most typically use the constructor injection, so the dependency is injected to a class 57 00:04:58,870 --> 00:05:00,100 via its constructor. 58 00:05:00,490 --> 00:05:07,530 It is also possible to inject a dependency via a setter, but it is much less popular US in general 59 00:05:07,540 --> 00:05:08,950 having a public sector. 60 00:05:08,980 --> 00:05:13,630 These are risky business, but if we wanted it, it would look like this. 61 00:05:19,010 --> 00:05:25,250 And then we'll simply assign this property toward the object implementing ogre interface. 62 00:05:25,340 --> 00:05:33,320 We wanted to use here before we mentioned that classes should not be responsible for creating their 63 00:05:33,320 --> 00:05:34,280 dependencies. 64 00:05:34,700 --> 00:05:37,550 Well, who should be responsible for it then? 65 00:05:38,120 --> 00:05:44,330 Most typically, we have two places where we construct objects depending on our needs. 66 00:05:45,110 --> 00:05:51,530 If we need objects that can be constructed right of the program start, we can create them at the entry 67 00:05:51,530 --> 00:05:58,340 point of the application, like the main method and then pass them down to whatever cross that needs 68 00:05:58,340 --> 00:05:58,700 them. 69 00:06:21,960 --> 00:06:28,710 In this case, we create or object we need in the entry point of the application and then we pass them 70 00:06:28,710 --> 00:06:31,350 around to all classes that need them. 71 00:06:31,770 --> 00:06:38,570 Please notice that in the real life projects, the creation of objects is not done manually, but with 72 00:06:38,580 --> 00:06:46,140 dependency injection frameworks, there are mechanisms that automatically create dependencies and inject 73 00:06:46,140 --> 00:06:48,090 them to objects that need them. 74 00:06:48,420 --> 00:06:55,140 Dependency injection frameworks are configurable so we can decide what concrete types will be injected 75 00:06:55,140 --> 00:06:56,250 into objects. 76 00:06:56,610 --> 00:07:03,270 They can also be configured to produce one instance of some type or to create separate instances for 77 00:07:03,270 --> 00:07:05,130 each object that needs them. 78 00:07:05,760 --> 00:07:12,030 Some of the popular dependency injection frameworks in C-sharp are out of our own inject. 79 00:07:12,720 --> 00:07:16,620 The second place where we create objects are factories. 80 00:07:17,160 --> 00:07:23,280 Sometimes we don't want to create objects to the entry point of the application, but rather at some 81 00:07:23,280 --> 00:07:25,200 specific point of execution. 82 00:07:25,740 --> 00:07:30,030 This happens when we are not sure what objects exactly we need. 83 00:07:30,210 --> 00:07:37,260 For example, a concrete type may depend on some parameter or configuration provided at runtime. 84 00:07:37,680 --> 00:07:41,820 Sometimes we're not even sure if we will need those objects at all. 85 00:07:42,060 --> 00:07:44,970 In this case, it's best to use a factory. 86 00:07:45,400 --> 00:07:49,560 A factory is a class that simply creates objects of some type. 87 00:07:49,980 --> 00:07:51,180 Let's see an example. 88 00:07:51,870 --> 00:07:58,650 Let's say that in the personal data for motocross, we can either use the default formatting which we 89 00:07:58,650 --> 00:08:02,520 used here or formatting provided from the outside. 90 00:08:02,970 --> 00:08:09,600 The decision on which one will be used is done at runtime, and it depends on the value of a parameter 91 00:08:09,630 --> 00:08:10,200 of the form. 92 00:08:10,200 --> 00:08:11,010 What mattered? 93 00:08:18,410 --> 00:08:25,970 If the default formatting parameter is set to true, we'll just use this default formatting, but otherwise 94 00:08:26,150 --> 00:08:28,580 we want to create a format or object. 95 00:08:29,060 --> 00:08:35,210 There is no point in injecting this object into this class because it may happen that we won't even 96 00:08:35,210 --> 00:08:38,900 need it, so it would be a waste of resources to create it. 97 00:08:39,260 --> 00:08:42,200 But I don't want to create it here like this. 98 00:08:45,940 --> 00:08:52,060 Because this a gun would be against the dependency injection and would cause again all the problems 99 00:08:52,060 --> 00:08:56,200 we had before, when we created Roeger and people they carry, they're here. 100 00:08:56,560 --> 00:09:02,320 So I want to create this object right here, but they want the benefits of dependency injection. 101 00:09:02,890 --> 00:09:06,250 The solution is to use the factory first. 102 00:09:06,370 --> 00:09:08,200 Let's see the factory glass. 103 00:09:09,630 --> 00:09:12,600 It is, as you can see, it's extremely simple. 104 00:09:12,930 --> 00:09:17,100 It's just creating an object, implementing some interface. 105 00:09:17,490 --> 00:09:20,220 Let's use it in the people data for through glass. 106 00:09:34,690 --> 00:09:35,410 All right. 107 00:09:35,890 --> 00:09:37,630 Let's see again what happened. 108 00:09:38,020 --> 00:09:45,730 First of all, I injected an object implementing the 04 motor factory interface to this class because 109 00:09:45,730 --> 00:09:49,480 I don't want to go against the dependency injection design pattern. 110 00:09:49,990 --> 00:09:55,780 Then if this parameter is false, I use the factory to create a formatter object. 111 00:09:55,960 --> 00:09:59,440 And finally, I use it to format the people's data. 112 00:09:59,770 --> 00:10:03,490 Please note that the factory would dance on interface. 113 00:10:03,730 --> 00:10:10,270 So for testing purposes, we can provide a mock of the factory that would create a mock of an actual 114 00:10:10,270 --> 00:10:13,360 formatter motor because we use the factory. 115 00:10:13,420 --> 00:10:16,660 We don't need to create the filmmaker object up front. 116 00:10:16,960 --> 00:10:19,450 Maybe it will not be created at all. 117 00:10:19,540 --> 00:10:25,510 If the format method is never called with the default formatting parameters set to false. 118 00:10:26,020 --> 00:10:29,380 Of course, in this simple code, it wouldn't matter that much. 119 00:10:29,680 --> 00:10:36,760 But again, in a real life application, the creation of an object might be more complicated and performance 120 00:10:36,760 --> 00:10:37,300 costly. 121 00:10:38,170 --> 00:10:38,920 All right. 122 00:10:39,280 --> 00:10:45,370 We learned that dependency injection is a design pattern, according to which we should provide the 123 00:10:45,370 --> 00:10:50,500 dependencies that an object needs instead of having it construct them itself. 124 00:10:51,280 --> 00:10:56,770 During the interview, you can be asked what our dependency injection frameworks? 125 00:10:57,410 --> 00:11:04,570 There are mechanisms that automatically create dependencies and inject them into objects that need them. 126 00:11:04,930 --> 00:11:11,590 They are configurable so we can decide what concrete types will be injected into objects, depending 127 00:11:11,590 --> 00:11:13,000 on some obstructions. 128 00:11:13,420 --> 00:11:19,330 Some of the popular dependency injection frameworks in C-sharp are out of luck or indirect. 129 00:11:20,050 --> 00:11:27,190 What are the benefits of using dependency injection dependency injection the caboose across from its 130 00:11:27,190 --> 00:11:28,150 dependencies? 131 00:11:28,510 --> 00:11:32,740 The class doesn't make the decision what concrete type it will use. 132 00:11:33,220 --> 00:11:37,480 It only declares in the constructor what interfaces it will need. 133 00:11:37,810 --> 00:11:44,350 Thanks to that, we can easily switch the dependencies according to our needs, which is particularly 134 00:11:44,350 --> 00:11:48,790 useful when interpreting mock implementations for testing purposes. 135 00:11:49,480 --> 00:11:53,170 All right, so we learned about dependency injection. 136 00:11:53,530 --> 00:11:56,620 Thanks for watching, and I'll see you in the next lecture.