Factory Pattern in C# with Dependency Injection

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in dependency injection we typically put our dependencies in the constructor when our class is created our dependencies get created and injected however there are times we want to create our dependencies more often or in a different way one solution for this is the factory pattern in this video we're going to look at how to create factories for various needs in c sharp we will look at an abstract factory a factory for initializing class instances with startup data and a factory for instantiating different implementation classes based upon passing parameters with each solution we'll be implementing it inside of dependency injection for proper handling of dependencies now if you don't know me my name is tim corey and it's my goal to make learning c-sharp easier i do this by providing videos here on youtube multiple times per week plus i have a weekly podcast called dev questions i also provide courses on c-sharp web development and much more on iamtimcory.com the profits from those sales are what pays for the free content here on youtube so that everyone can have a great education in c sharp not just those who can afford it now in this video as with most of my videos i might create some source code if you'd like a copy of the source code use the link in the description below let's jump over to visual studio and we're going to create a new blazer server project and that's just simply because blazer server has dependency injection already set up and we have pages that we can very easily modify so let's hit next and we're going to choose to call this our factory uh factory pattern is the uh name and private pattern app how about that let me hit next yes.net six no to all any changes here so we'll leave us all as defaults and hit create okay once this is created we can close down the main page here let's start by creating a folder called sample so this is going to be very much a demonstration video not a do everything exactly the same my production and the difference here is because i'm going to create really simple little classes to show off the different ways of using factories but you're going to have to figure out what your classes really look like because i don't want to create a whole bunch of complexity that we don't need okay so i'll point out the differences versus um real life i guess you could say but the differences really are about the actual code in the classes we're creating so we're going to create samples just to be very clear these are samples we're going to use i'm going to create a class in here and this class let's just call this sample one and we'll put a semicolon here to change it to a filescope namespace and for sample one i'm going to put um one property and let's create a date time property and call it current date time and we'll say equal new uh date time dot uh now like so um actually it's going to yell me does not exist in the date time that's because i said new there we go datetime.now so that just gives us the datetime.now actually let's do this let's just do a two-string and keep our um keep it easier which means this should be a string okay and what that's going to be is just a a clear string that is the current date and time so whenever this gets created we're going to see the date and time for what else created that's it okay so when it's created we're going to get this it's going to put it in this value now let's create an interface for this extract an interface in the same file called sample1 or i sample one and again this is where again i would not put this in the same file but this is a sample so that's why i'm doing it in the same file so now we have our interface and our implementation like this would be a real class but again this is just for demonstration purposes so let's come down here to our program.cs we'll add a using up here so using a factory pattern dots samples like so and then in our services we're going to add builder dot services dot add transient which means get a new one every time for the i sample one and the implementation is sample one so whenever we ask for an i sample one we get this implementation sample one this is dependency injection 101 i have a whole video on dependency injection i have a whole course on dependency injection.net that would be helpful but this is just adding one dependency to our dependency injection so let's go over to our pages we'll go to the index page we're going to clean up this page where i get rid of most of this stuff and we're going to have an ejection here so we're going to say inject and then we'll say i want to inject an i sample one which i can add a using statement for here or i can come down to my shared oops imports and say using factory pattern dot samples i'll be doing multiple of these so it makes sense to do and we'll call this sample so i have my sample one and here i can say right below hello world let's do an h2 that says sample dot current date time so this prints out whatever it said from sample one all right so let's let's make this run just to see that it works and just see we have a dependency that's in fact being called by um dependency injection there we go so we have our dependency it's working it's generating for us a string and if we come notice it's it's 2 13 27 it's 2 13 27 2 13 39 there we go uh 42 44. so every time i go back to the same the page it's a different value because the fact that it's getting a new value from dependency injection so that's what the add transient does however what if i wanted to have this get this value or get an instance of this i sample one more than once on this page so if i came down here in the code section and i said um every time i click the button i want to let's put a button down here uh class equals btn and such a btn primary and we'll say um at on click equals we don't have a method first yet we will let's call this git new time and we'll have the get new time method private void get new time like so and oops there we go so this method what's going to do is get a new version of this time and so we'll put down here um you know some way of we want i sample one and we're going to call this um uh current time it'll make it nullable but every time you click the button i want current time to be equal to i guess sample like how do i get a new version of this all right so i want a new version of this every time and then what i'm going to do is instead of showing up here sample i'm going to say the current time so if i run this and wait for it to load well first of all it says audit reference not such an insistent object of course um i can do this that says hey if it's not null then do this could wrap it and if statements that would be better for um what we see in in uh blazer but that's okay so get new time okay so go ahead time cool i click the button again as many times as i click it it gives me the same value over and over again because i'm getting the same it's the same instance i don't have a separate instance so how would i get a second instance from my dependency injection and this is where people get off often get stuck with dependency injection they say oh i don't know maybe i'll have to just say you know create my own instance where instead of doing this i would say equals new and i'd say sample 1 like so if i did that in theory it works so if i say hello world i click it i click it again notice it's 8 now now as 0001 i'm getting different values but the problem is i have now instantiated this manually i have taken it outside depends the injection and i'm not declaring my dependencies up front and this is not a good thing because now if sample one had dependencies they wouldn't be pulled from dependency injection either so that creates a whole mess we don't want to do that so how do we get a new instance from dependency injection properly well there is a way of doing that it's called a factory in a factory its job is to create instances properly from dependency injection let's do the very very simplest version of a factory so we have over here the we've referenced the sample one right well let's add one more builder.services.add singleton you don't need anymore singleton i'm going to ask for a funk of type i sample one and i'm going to close this out like so and then i'm going to say in here x arrow open close paren arrow x dot get services for i sample one let's unpin this you can see the whole thing like so and then i need to put open close paren at the end like so and a semicolon now let's yell me right here because it could return null which i'm going to say no it can't that's the exclamation point saw my previous video on how to handle nulls this is one of those instances where we know better than the compiler because we know that yes there is a sample one in the services therefore it's not going to know so what is this well this is technically a factory now it's the very simplest of factories and it's a little bit complex to read so let's talk through what it is now if you don't know a funk what its job is is to be what's called a delegate and a delegate i have a whole video on delegates here on youtube but a delegate is a a method that you pass around like a variable and the purpose of it is to allow somebody else to call the method not you don't call a method right here you let somebody else call it later so this method right here this is saying hey put this independency injection so when you ask for a func of i sample one then you get back an instance of this which this has one method which has no parameters and its job is when you call the method that you it actually goes out to the services and gets an i sample one okay so it still uses dependency injection it still declares its dependencies right up front but what this is doing is allowing you to create this later because this does not get run when you put it in dependency injection it gets run when you call it let's see as an action because i know it's a little bit confusing so this funk of sample one okay we're gonna copy this and over here in our index instead of asking for an i sample one we're going to ask for funk of i sample one we'll call it factory i'm gonna say down here factory execute that that's what the parens are for okay so this is a delegate of being passed in it's a funk of i sample one it's a delegate we can call that delegate call that method here so by saying we pass in factory as the dependency that's been injected and we're now running that dependency which gives us current time yes this is a little bit confusing if you're not familiar with delegates and how they work hello world get new time okay we're 2127 2130 2131 but the difference here is these dependencies are coming from dependency injection they're not coming from creating new instances manually the difference is that if we had a dependency inside of sample one that it would be resolved through dependency injection so we can still have dependency injection throughout our application and yet we can get an instance whenever we want of that i sample one now let's be clear before we go on in that this is not something you do all the time this is something that you do in the rare cases where it's necessary there are a few times when factories are necessary in fact if you've worked with calling apis inside of your c-sharp application you've probably used the http client factory because it creates http clients for us and it handles their lifestyle their lifespan reusing them closing them out properly and so on that factory creates for us http clients using dependency injection but doing so in a way that does some work on those dependencies for us so this there is a case for it but it's not an everyday thing so be careful when you're learning something new like this that you don't just say oh goodness i'm going to use this everywhere i want to create new models for example well probably models shouldn't be in your dependency injection because models are just like data holders i mean you don't put int and string in dependency injection you just create intense string well it's no different really with models usually now there's cases where yes a model might go into dependency injection if it has some logic in it or other things like that but just be very careful you don't overuse this okay so with anything new don't think that just because you know you have a hammer doesn't mean everything should be looked like a nail now so this is just a new tool for your toolbox if you haven't used factories already but let's dive deeper into how to create an abstract factory because this right here uh it's a little complex okay and it's a little complex to see where you're saying funk of i sample and then calling it here this is not as clear as it could be and there's ways to make it clearer so let's do that so we're going to create a factory now what i'm going to do is i'm going to put this into let's go to a new folder here and i'm going to call this factories and i'm gonna put the factories in imports.razer um which actually exists in factories yet that's okay so it'll yell me right now because there's nothing in there we'll get one in there and we'll also put this as a using in here oops there we go and again it's going to help me until i put something in here so let's put something in here where i create a new factory so let's call this abstract factory all right and by the way now uh program.cs doesn't yell at me anymore and neither does the imports because they actually have something in that namespace okay so we have our public class abstract factory now i'm also going to create other things in here other classes in here at the same time and that's something that again i want to point out that normally i create these in separate files but i want to keep it all together for you so you can see everything in one spot for this demo because we're going to do multiple of these factors so let's come up here to the top and i'm going to create a public static void add abstract factory okay and this is going to be an extension method but first it takes in two generics t interface and t implementation and then let's unpin this let's um close that out too we're going to say this i service collection services and then we're gonna have some limitations on our our two generics so this could be uh t and u but i call it t interface and t implementation to show that these are generics and the first one's going to be an interface the second will be an implementation so where t interface is a class and then where t implementation is a class and it's a t interface all right so for instance just to make sure we're on the same page here if i pass in i sample one and i sample i'm sorry i sample one and sample one that would work because i sample one and sample one well i sample one it technically is what's called a class you know it's an interface but the implementation is of type interface so sample one is an i sample one all right so that's limitations on our generics if you've not dealt with limitations on generics yes you can say what they can or cannot be and you have some limited uh ability to kind of dial in what they can or cannot be in that particular generic now inside of this polystatic void again this is an extension method on the i service collection so we can extend the services here this just makes things easier we could do it all right inside of our services we're not going to we're going to do it all here to make it clearer so we're going to create or fill this out so first of all we're going to say services.add transient i t interface i'm sorry t i interface and t implementation like so so that this right here is the equivalent of this line right here it's going to do the same thing but that is their guarantees we actually have that implementation in our services collection because then we're going to say services.add singleton and funk of t interface this looks familiar x arrow open close paren arrow x dot get services or get service t interface open close parens yes we know it's going to be in the dependency injection so this func of t interface that's what we did right here okay but instead of saying funk of i sample we said t interface we don't know what's being passed in this is an abstract factory and then finally we're going to have one more and that is services dot add singleton and this is going to be an i abstract factory of type t interface and we're going to have a factory an abstract factory of type t interface now we and that's i probably have some missing um something oh well i haven't actually named these things that's why it's yell at me so let's create these we have abstract factory we don't have an abstract factory of that correct type so let's create of type t all right and we can create an interface for this let's do this again in line public interface i abstract factory of type t and then we're going to implement that here okay and let's say i have an extra close angle bracket there there we go let's clean this up a little bit since it messed up okay so we have this line here and i'm sure this is probably hurting your brain so let's talk through what it's doing we're adding a new class to dependency injection it's a singleton and the class the implementation is abstract factory of t interface well we have an abstract factory down here of type t which t and t interface that's the same thing as just a generic okay so in our case let's just bring in these two lines here just as um as comments so i'm going to say here just we can see what this might look like so when if we were trying to do these two lines here we'd be saying i want builder dot services dot add abstract factory of type i sample one and sample one is the implementation detail okay that's what we'll be doing to call this so we'd say add an abstract factory of type i sample one and sample one so there's the interface and the implementation so t interface would be i sample one so down here we're saying i want you to have an i abstract factory of type t interface well that's sample one and then the abstract factory is of i sample one so down here we'll be passing in i sample one so how is what is this what do we do here well we're gonna have a constructor our abstract factory and we're gonna pass in a func of type t and we're going to call this our um it's called factory and let's do a control dot here to create and assign the field so now we have this private read-only funk of t remember this it's the same thing we did before over here where we said funk of i sample one and we have called this method so the factory created we have called it we're gonna do the same thing inside of this class so let's create a method public return type of t create and we're going to say return and run the factory so we have this factory here which is a funk of t we're going to return the execution of that which returns the actual object so we've returned the object that it's creating which in this case that funk of t is going to create a service of type t interface which in our example is i sample one which returns an instance of sample one so it's the same work we did here it's just we put it inside of a a special class called abstractfactory that has a create method and the reason for this is it makes it a little simpler and easier to understand yes this code is a lot of um generics and delegates and interfaces oh my but once you kind of grasp it once wrap your head around it and take your time wrapping your head around don't worry if this first second third or fifth time this is confusing take your time walk it through step by step over and over again sometimes it's best just to create it just to do it and then in practice not in production in practice and then walk it through over and over again and you know step through the code but what that's going to do is create for us our new t whatever that t is in this case our i sample 1. now for our interface we actually have to move this down so t create that's the only thing in interface is just the create method so now we have this um this plug static void that is going to add these three things to our services list now i do have one issue here this is yell at me here saying hey you cannot the namespace cannot directly contain members such as fields methods or statements and yes i have missed one step let's cut this out and say public static class abstract factory extension okay because i have to have this method inside of a class it has a static in order to have a extension method so i just missed making it a class so we now have this um abstract factory collection extent or abstract factory extension which is just a class we don't need to even worry about what the name of it is but this method right here will allow us to create an abstract factory so let's go back let's save this and let's come back here and we're gonna comment out these two lines we don't have them anymore okay and instead we're gonna say builder dot services dot add abstract factory now if you don't see that in the list it's probably because you can add the using statement up here for it i'm going to add an abstract factory for i sample one and sample one is the implementation so this looks very very similar to add singleton or add transient but now it's at a factory for this which is going to register these as transients okay it's going to do that inside the method it's also going to register our our func and then it's going to register the factory itself which calls the func so let's see how to work with this instead of index.razer so let's um get rid of this let's actually just get rid of it and slash slash doesn't work in razor anyways it's actually the um there's a couple different ways of doing um yeah comments that's the way i'm looking for um but instead we're gonna say inject i abstract factory of type i sample one we'll call this factory all right so we've injected now an i abstract factory of type i sample one so we're still being very clear as to what we're depending on and then down here we're going to say factory dot create and that factory creates an i sample 1. so that's our sample one right here now if we run this and wait for it we have hello world we have our time we have our time again we have our time again every time we click the button we get a new time so it still works the same it's just it's very clean right now where we just asked for a factory of it and hit the create button the cool part is that it's it's super simple it's super simple to add here and we can add this for as many different types as we want let's just say we created a sample two so let's go to samples we're gonna say add class sample 2 and let's put our semicolon here and for public class sample 2 we're going to have a well let's do the same thing as sample one because you know why not but the the current date time we're gonna do it a little differently actually let's do this let's do a random value here uh prop string that's an int uh random value and we're going to say constructor and we'll say random value equals random dot share dot next and we'll say from uh one to uh a hundred which actually just you know um i always i always say this but max value you'll never get a hundred you only get 99. it's up until the max fight so you'll never hit the max value you're always one shy of the maximus if you want 100 included you have to say 101. just see now so that's a random value and then we'll do a control dot to extract the interface we'll do the same file again again it's a sample so we have our in random value so now if we want to create this in a factory well we go to program.cs and we say builder.services.add abstract factory i sampled 2 and then over here on index page we can say um inject i abstract factory i sample two i'll call this sample two factory and we'll say the h2 let's get our i sample 2 nullable um random value so we'll say here at random value if it's not null and the random value because we have that right uh let's put in front of it the random value is that okay so down here we don't have anything but in our get new time let's use the same button because again this is a sample so random value equals sample to factory dot create let's run this again so i have to rewrite that abstract factory so get new time there's the random value there's a random value there's a random value there's a random value and so on so every time i click the button we're gonna get a different random value even if i click it multiple times in a second i can get a different random value every single time and just you know i want to point this out real quick random means random that means you might get the same value more than once in a row because it's has the same opportunity to have that same value come back up as it did the last time so just so you know some people think that random means to be a different value every time it can be the same value and that can be the random result so just to be clear there's actually an issue i believe was spotify had to change the way they did their shuffle because people thought it wasn't random when in fact it was so random that sometimes the song would play twice in a row so they actually had to change their shuffle for that so just clear that up about random um all right so we've seen abstract factory and the abstract factory works really great if all you want to do is get a new instance of something so every time you ask for you say create and get a new instance of it but there are times when maybe you you want to create an instance that is populated pre-populated with some information you know so normally you're used to having a constructor where you pass in data but with dependency injection your constructors pass in the um the things you want from depends injection only so how do you pass in data to a constructor well that's you know quite confusing to people let's create a factory that's not an abstract factory it's a factory that is custom built for one particular type that is designed to give us data inside of our class at startup so let's do that now let's start by creating a new entry in samples and we'll call this user data now this class right here is going to represent a class where you need to initialize it with certain data already in it and the uh the data we're gonna talk about is name that's the only thing i put in here but that's gonna be how this class needs to be initialized the class needs to have a name populated in it now typically this wouldn't be just a model it would be have methods attached to as well but in this case we're just going to put a one property in here to kind of stand in for any class that needs data brought into it at the start so we're going to say let's make the the name nullable oops there we go not there string question mark there we go and we're going to say let's do control dot here extract an interface in the same file called i user data and it just needs a name that's it all right so that's the the whole setup for using that's our sample data then we're gonna come over here to our we had an abstract factory we call it abstract factor extension let's create a new class we'll call this the um uh let's call it uh generate class with data factory how about that it's a great name i know but this at least gives us some information on what it's doing we'll call this extension so just like here we have our public extract factory or add abstract factory we're going to have our our add generic class with data factory like so but we're not gonna get there yet instead we're gonna do is come down here below and we're gonna create our factory first so public class and we'll say user data factory like so and then we're going to have a constructor that takes in a func of i user data which control dot to add the using statement for that and we'll call it um we call over here we called it um our factory so let's just call it factory as well and then control dot to create assign that field okay looking very very similar to we had e4 and we're going to say public i user data create string name okay so this is the create method but we're taking in a name var outputs equals and call that factory so that creates the instance of our object but that instance does not have data in it yet no problem we're going to say output.name equals name and then return output so you can see what we're doing here is we're creating the instance we're creating into the factory so that when you pass this in we can then update the instance with that right away and then we can return the instance to you so that's our factory so let's do a control dot here extract an interface in the same file and that's our our interface it just has the one i use data create method and now we can get to actually setting up our our method here so we can say public static void and by the way this needs to be static class so add generic class with data factory and we're going to pass in this i service collection called services let's unpin this you can see the whole thing and we're going to say just before services dot add transient use our data see the difference is we're not using generics here and pass on you to do whoops and then services dot add singleton funk of i user data and then we're going to say the same exact method x dot get services of i user data and yes we know it's going to be not null and then finally services dot add singleton and this is going to be the i user data factory and the user data factory so if you look over here at these three right here i'll just copy these and come over here and we'll comment them out these three right here are the same as these three right here the difference is okay they're almost the same the the difference is that instead of using a generic i'm using a specific class because this deals specifically with eye user data and the reason why it's specific to that is because the factory has some specific code that only works with eye user data and that's this line right here and the parameter being passed in but that's it so the rest is the same and we can just say we can call this over on our program.cs builder.services.com add our generic class we are add generic class with data factory so we're not passing in what specific types because that just takes care of it types for us it takes it's the um i use the data so it still uses dependency injection it's still adding this dependency injection it's still requesting that from dependency injection with our func and it's still adding our factory dependency injection the difference is that it's only for one it's not an abstract factory it is a more concrete factory type so now with this concrete factory type we can request an i user data factory let's go over to our index.razer and let's inject our iu data factory and say user data like so and now we can ask for a our we have our i use our data and we'll call it user and again i'll make it nullable and then the same button here um actually no you know what let's do this on startup so protected override uninitialized and we're going to say user equals and we have our user data factory so user let's call user data factory so we're clear here so use the datafactory.create we have to pass in a name so tim court like so so now we can put up here hello add user dot name all right and yes we'll make this um do nothing if it's null let's run this wait for it and it says hello tim corey because this came from the past injection but that was added to based on what we passed in every time you pass something in so every time we do this we could pass in a different value and get a different instance back with a different name in it so that's a way to have a non-generic non-uh abstract but a factory that we pass data in to instantiate our our class now there's another thing we can do here as well and that is maybe you want to get a different version so you ask the factory and say hey i want this interface but here's a specific implementation i want if we have more than one how do we do that well let's implement that as well so we can come over here and let's create class and we'll call this different implementations factory and i'll mark this as file scoped and we'll say extensions like so make it static and we're going to do something very very similar to 884 so let's create a a factory first down here public class and again i just want to reiterate this i know that i says over and over again but please create your your classes and your interfaces all their own files don't create them all in one file like i'm doing here but this is great for a demo to keep everything together for you you can see you can see different pieces that go together in one spot so public class vehicle factory now in order to have a vehicle factory we should probably have some vehicles so let's create some classes um i'm going to say vehicles plural here because in here we're going to create multiple vehicles we're going to create a car and we're going to create a truck as well and a van too so let's start off with prop string vehicle type we're going to say this is a car this is one way of identifying classes is by creating a property that identifies this you can also say type of if you want to go that far in order to not have in order to not have to look up what the type is through reflection so we can just have a property that declares it or you could do um something else but for this we're just going to have the type of vehicle equals car and call that good and then public string start like so this method just returns return um the car has been started okay that's again very very simple sample class let's copy this twice and this is truck the trunk has been started and this is a truck again yes this is not real life code because the fact i could abstract this all the way into one class and yada yada that's not the point the point is it gave you a sample of how you could do it in real life with real code where this would be different so i have the car truck and van and each of them has a vehicle type which is truck car trucker fan and each one has a start method which says that the whatever vehicle it is has been started that's it now let's extract an interface in the same file called i vehicle so we have our i vehicle and we already know that all three of these implement so let's go ahead and apply these all three now what if you want to put this in a dependency injection you have one interface that has three different implementations we're gonna see how to do that and we're gonna see how to do it even with a a factory so let's create a factory that handles creating these instances so we have uh different implementations yeah that's it so we're going to create a constructor and a constructor we're going to ask for a func of i innumerable of type i vehicle which control dot to add the using there and we're going to call this factory control dot to create a center field so our factory and we ask for an innumerable vehicle which means it's going to give us a list or a set of vehicles why we want to set well because we're gonna put all three independent injections we'll see that so for our public eye vehicle create we're gonna pass in the name and we're going to say var set equals factory actually it's factory which runs the the creation there it gives us a list or a set an innumerable of i vehicle and then we're going to say i vehicle output equals set where x arrow x dot vehicle type equals name first so it's going to look through the list and find the one the property that matches the name you've passed in now i do want to point out that if you pass in we're doing we're doing a string comparison which is case sensitive and we're doing a lookup on it so if you pass an all lowercase car it's not going to find it and it's going to throw an exception because it says first you don't have that so you would want to do a whole lot more work here around making sure that you're passing in either a new and doing some still some checks on that to make sure it's a valid anum or doing something else for your lookup but this will work for our demo so we're getting our vehicle return the output okay so that's our factory let's go ahead and create the public static void and vehicle factory this i service collection services and we add services add transient i vehicle car and let's just copy this line we run into it three times trunk van now we're gonna add these three things to dependency injection and some people say well wait a minute you can't do that you've got three different types how do you ask for them independence injection well if you ask for i vehicle just one you're getting back van because the last thing added but we're going to ask for an i innumerable of i vehicle which notice right here innumerable of eye vehicle and what that will do is give us all the instances of i vehicle independency injection so car truck and van because all three of those now we can say services dot add singleton and it's a funk of i innumerable of type i vehicle nope nope nope nope intellisense or intel code actually got ahead of me there so it's a funk of an interval of vehicle which means i need three closing angle brackets and then i'm going to say our same let's unpin this we have a little more space x arrow open close parens arrow x dot get service and the survey says i innumerable of type i vehicle and then we come to the end here and we have an open close paren and our semicolon at the end and before that we put our exclamation point saying yes we know this could be null but it's not trust us it's not let's actually put this in the next line down just to give us a little more space so there's our factory um and then let's create our actual vehicle factory so services.add singleton i vehicle factory oh we can add an interface with this control dot extract interface current file i vehicle factory which just has the create all right like so so now we have our singleton for i vehicle factory which chooses the right vehicle to create for us which technically what it does it gets all three from depends of the injection and it picks which one you want which er not terribly efficient especially if you have a thousand of them um you probably shouldn't you should probably think of a different way of doing that but um if you have a couple that might have a bad idea or you can go another route um with asking for funk of i of carr or in funk of truck and funk of van ivan and then you get the right one from that so there's different ways of going about this but this is the simplest way but yes it does get new instances since they're all transient it gets new instances of all three of these and only returns one so if that's a problem then you can go about a different way like using the funks but with this we now have everything set up so let's close all this out man i got a lot of tabs open we can pin this again we can go back to our index page our poor index page was getting overloaded by now and we're going to say inject and this is a i um i'm not sure this was anymore i vehicle factory yep vehicle factory and we also had add dependency injection we haven't done that yet i don't think nope builder dot services dot add vehicle factory there we go add to dependency injection now over here we can say i want an i vehicle it's nullable vehicle and let's do it on initialized vehicle equals vehicle factory dot create we have to pass in the right string that's magic strings and all the rest not the best but it works let's say truck and then up here we're going to say after username who drives a and then no let's yeah let's do this at vehicle question mark dodge um we have the start method and vehicle type it's a vehicle type and then we'll also have an h2 down here that is at vehicle question mark dot start so let's run this wait for it to load hello tim corey who drive the truck the truck has been started okay we did that based on the fact we asked for a truck let's ask for a car instead and tim cory who drives a car and the car has been started so i get a different instance based on what i've asked for so i could even you know i could change names sue storm and van just to show you all the different options you could do hello sue storm who drives a van that they have been started um and again i can change you know one thing at a time or both and get whatever instance i want back depending on what i ask for so that's how you can use a factory pattern to get a specific instance based on your request as well so the difference here and one of the things that some people say is well you know what i could have done this a lot less work what i could have done is i could have passed in if we look here uh let's go at the doesn't matter which one you are quote-unquote passing in the i-service collection that's our dependency injection container and so you're saying well i could pass that container in do a get services whenever get serviced whenever i wanted so i could just pass in i service collection to my index page without having to do all these and then i can just ask where i want down in the code and yes you can that's more of a service locator pattern which is actually an anti-pattern usually not always but usually and the reason why it's a problem is because you bury in your code what you're depending on whereas here we're saying exactly what we depend on we depend on in this case i vehicle factory if you look at the the vehicle factory it depends on these three things this and this so it declares right up front what it depends on so we have a clear dependency tree we're using dependency injection we're not using just a service locator pattern where we're asking for services buried in our code somewhere we're very clear up front what we depend on so that's the difference here and this is why we use a factory pattern as opposed to just passing around that iservice collection now you may ask about um this where it's getting the service as you know in the method itself but this is declaring up front what it depends on in our dependency injection so it's being very clear now the other thing i want to point out is i have not really buried but i have put these behind extension methods so when you look at program.cs you see these three uh are these yeah these three extension methods abstract factory generic class of data factory and vehicle factory but we don't have to we could have taken the extension methods themselves so this right here we could have instead taken this code and put it right in program.cs in this spot and that would work just fine so if we if we take this let's uh copy this and if i were to comment this out instead i'm going to paste in this which i have to change to builder.services i could replace all but no big deal so this would work just the same as this so if i were to run this right now i've commented out add vehicle factory i still see that sue storm drives a truck and a truck's been started because that's all the extension method did was kind of abstract away this into one method called add vehicle factory it's even easier or nicer when you have the abstract factor which is you know lambdas and generics and all the rest you don't have to put it in your in your program.cs you can just put that one line in so one line a whole lot better a whole lot cleaner and easier to use continue editing and stop i the thing was still running for some reason so that's how to work with a factory pattern again i want to be very very clear here that this is something that you don't use every day necessarily it's something that you want to first and foremost depend on what i call regular dependency injection where you just inject the dependency at the constructor and then you do work with that dependency but there are times when you need a factory where maybe you're uh creating something over and over again one of the examples that i came across recently which we're going to cover in a future video is when you put wpf behind dependency injection so we're gonna have dependency injection in wpf but there may be times when you create a form from another form over and over again every time you click the button you create a new instance of a form well you can't just put that in constructor injection because you need more than one instance how do you do that well you use a factory in order to do that and so we'll do that with an abstract factory probably so there are times and factories necessary and there are times when this makes sense just don't think that it's used every single day for every single project it's not this is one of those things where whenever i cover design patterns i'll be very clear on design patterns design patterns are typically complex and the only reason that you add a complex design pattern is if the complexity of the design pattern is less than the complexity of not using the design pattern so don't think of design patterns is something you do every day it's something you do when you have a complex situation that you need to make a little less complex and a little more scalable over time but if it's not that complex yet don't use the pattern so very very clear there with that so factory pattern can be very very useful personally i like the abstract factory pattern a lot because there when there are times when i need it it's just drop in i don't have to worry about um declaring all or doing all the work into the patterns of the factory itself i say drop in the abstract factory pattern and then i reference it it's also very clear what dependencies it has right up front because i sample one and sample one that's what it's it's depending on so very clear i like it a lot the other two there are times where necessary but i really prefer to see the abstract pattern used if you need to instantiate something with star data or if you need to have a specific class returned based upon what you're doing there may be a better way of doing that but if not then the factory patterns here that i've shown will work well all right if you have any questions leave them down in the comments maybe someone can answer them maybe i can well it depends um but if you have any thoughts on the factory pattern i'd love to hear them as well thanks for watching and as always i am tim cory [Music] [Applause] you
Info
Channel: IAmTimCorey
Views: 53,280
Rating: undefined out of 5
Keywords: .net, C#, Visual Studio, code, programming, tutorial, training, how to, tim corey, C# course, C# training, C# tutorial, .net core, vs2022, .net 6, factory pattern
Id: 2PXAfSfvRKY
Channel Id: undefined
Length: 67min 32sec (4052 seconds)
Published: Mon Jul 11 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.