- Overview
- Transcript
2.1 Factory
The factory design pattern is one of the most basic and foundational patterns. The goal of the factory pattern is to provide a mechanism to create objects, with a dynamic creation process that is able to determine which type of object to create at runtime.
1.Introduction2 lessons, 04:27
1.1Introduction01:39
1.2Prerequisites02:48
2.Creational Patterns5 lessons, 52:47
2.1Factory10:16
2.2Abstract Factory12:24
2.3Singleton09:09
2.4Prototype09:18
2.5Builder11:40
3.Structural Patterns7 lessons, 1:05:54
3.1Adapter10:07
3.2Flyweight10:33
3.3Proxy05:53
3.4Bridge10:35
3.5Decorator11:44
3.6Composite09:43
3.7Facade07:19
4.Behavioral Patterns9 lessons, 1:25:42
4.1Iterator09:32
4.2Command07:48
4.3Chain of Responsibility13:47
4.4Mediator08:16
4.5Memento08:53
4.6Interpreter14:31
4.7Observer08:58
4.8Strategy07:36
4.9State06:21
5.Conclusion1 lesson, 02:42
5.1Conclusion02:42
2.1 Factory
Let's begin with one of the most common and fundamental patterns that you're going to see out in the wild, and that's gonna be the factory pattern. So, what we're gonna do is we're going to open up Xcode and we're gonna start by creating a playground. So, let's take a minute and let's talk a little bit about what exactly the factory pattern is. The factory pattern allows us to create objects of a certain type and be able to define or really identify what that type is at runtime and not necessarily at design time, or compile time. The nice thing about this is that makes our application much more flexible and allows us to actually increase the amount of testability that we have in our code. So, let's go ahead and see what exactly the factory pattern looks like when it comes to Swift. So I'm gonna create a new playground here and I'm simply going to call this FactoryPattern, and we're just gonna leave platform as iOS. And then let's go ahead and pick a location, and I'm going to create a new folder on my desktop, and I'm gonna call this DesignPatterns. And then within there, I'm gonna create one more folder and I'm gonna call this creational. Because the factory pattern has to do with creation of certain different types of objects. And so, it's labeled as a creational pattern. So, let's go ahead and hit Create there. And then within here, were going to now be able to start creating a little bit of a factory pattern. So, let's start with a very basic concept. Let's say, we're dealing with a series of shapes and those shapes all conform to a simple or a similar concept or idea. And in the world of Swift, that's known as a protocol. So, we're gonna start by creating a protocol and we're gonna call this shape. Now, this could be any sort of concept you want. I'm simply picking shapes, cuz it's fairly easy to understand. Now within this protocol, we're gonna define a single function. It's gonna be called draw. It's not gonna take any arguments and it's simply going to return a string as an example here. So, let's just say that any sort of class or object that is created from the shape protocol is going to have a draw function and it's going to return the operation that it's doing. Maybe it's drawing a square or a circle, or whatever sort of shape we're dealing with. So, let's go ahead and start by creating a couple of different classes. So I'm gonna create a class here and this first class is going to be a rectangle, and it's going to be an instance of a shape. And so because of that, we are going to need to define this draw function within in here and this is simply going to return drawing a rectangle. Pretty simple concept. Now, we're actually going to do a similar thing. We're gonna create another instance of a class here, another class definition. And in this case, it's going to be a circle. It's also going to be a shape. And in this case, we're gonna say, drawing a circle. Now, you can see here that we're gonna be dealing with two different classes that are both going to be implementing the shape protocol. So we can see that at design time here, we have a couple different options when we are dealing with a shape. But at runtime, we're gonna be able to define which one of those shapes we want to create that are both going to be implementations of the shape protocol. So now at some point in our application, we're gonna need to be able to create some sort of shape. Now when we're dealing with a factory, we're typically going to be dealing with a factory that's going to be creating some sort of instance of an abstract idea or of a protocol. So a lot of times, what you're gonna see here is when we're creating a class. We're gonna be creating a class of a shape factory. So, we're gonna be creating the factory at the protocol level not at the specific implementation level. So now, we're gonna be creating this class shape factory. And within here, we're simply going to create a single function and we're just gonna call this shape. Because we wanna create a shape or you can call it create, that would work too. So if I were to say create, that's pretty common. And we'll say for and what this is going to take in is, it's going to take in a shapeType that we can specify at runtime and it's going to be a string. And this is going to return and instance of that shape protocol, but it's going to be optional. Because well, I'll show you in a minute. So now, we have our shape factory and we have a create method. So now, we need to do something in that create method. So typically, what you're going to see in most programming languages and Swift is really no different. We'll can some sort of condition logic in here. In this case, I'm going to do a switch statement. So in here, I'm gonna be most interested in my shapeType that's being passed into my function at runtime. So I'm gonna say, my shapeType dot and I'm going to take this down to lowercase. And once again, I'm gonna show you why in just a few moments. And now, we can start checking for things. So in this particular instance of a shapeFactory, we're only gonna be dealing with a couple different types of shapes. Now, I'm only using these rectangle and circle as an example. You could create additional concrete types that would be different types of shapes. So you can add diamonds or a rhombus, or any dodecahedron. Really, whatever you would want. So, the concept here would still be the same as long as they're all implementing that same shape protocol. So in this case, we're going to say that if this is rectangle, then what sort of operation do we wanna do? We're going to return a new instance of that rectangle class, because it is implementing shape. Also, we're going to create another case statement here. Because we can also handle circle. So in this case, we'll say, if it's circle, what do we wanna do in that case? Well, we're gonna return a new instance of a circle. So as you can see here, this class and its create function is going to help us to determine what type of shape is necessary at runtime and then give us the appropriate one that's going to have the proper functions within that are defined within shape. Now for some reason, we introduce a shapeType that is unhandled in this In this shape factory. What do we wanna do? Well, that's where we're going to handle this default. And in this case, we're simply going to return nil. So we'll say, return nil like that and that's just something that we're gonna have to handle within our application code. So now, imagine we're running our application or we're designing our application. And in some spot, we're going to need an instance of a shape. But whatever type of shape is gonna be defined by things that the user's doing, so maybe we need a rectangle or maybe we need a circle. And during the flow of that application, we're gonna need to retrieve the appropriate one. So, how do we do that? Well, in this case, at some point along the line, we are going to have an instance of our factory. So we're gonna say, let factory be equal to a shape factory just like that. And then at any point in time, we can ask that shape factory for a specific type by name. So in this case, I could say, var shape is going to be equal to factory and I can say, create and I wanna create a shape for a rectangle just like that. So once everything runs here, you're gonna see I'm now gonna have a shape here that's gonna be an instance of a rectangle. And if I wanted to prove that again, I could simply say, shape.draw. And you should see on the outside here, I see drawing a rectangle and that's because the concrete implementation of the object that I requested is a rectangle. And it says, drawing a rectangle. So now because shape is a variable after this, I could go ahead and say, all right. Well, now I want to go into my factory and I want to create a shape for circle. And I'm gonna make this all crazy cased here, so that I can prove to you that it's a good thing to not be case sensitive in a lot of instances within your factory. Because if for some reason you are and you pass in the wrong type of the sting or whatever you're requesting, then bad things can happen. So, I'm going to support all of these things by doing lowercase. So now, I have an instance of my circle. And just to prove that, I can say, draw. And on the side here, I should now get Drawing a Circle and I do. And now, we can also pass in something a little bit different. I could say, shape equal to factory dot and I wanna create this time maybe for a diamond. And in this case, you can see that since I am not supporting diamonds within my application and consequently within my factory, I'm not gonna get anything back. So, I have to be kind of conscious of that. Because when I say, coming down here into my shape and I say, draw, I'm not gonna get anything out of this simply because I don't have support for a diamond. So as you can see here, the basic concept once again of the shape factory's when you wanna create during runtime, the concrete implementation typically have some sort of generic protocol or an abstract based class or something like that. It's helpful to create a factory to do that for you, so that you can determine what type of objects are necessary to be created at runtime. The other nice feature of a shape factory is I can then create instances of this shaped factory and pass them into the initialization or the constructor of other classes in my application and then I would also at that point, be able to mock the shape factory or create fakes for that shape factory. And say that every time I pass in rectangle, I can spit out a specific testable instance of that rectangle, so that I can then increase the testability of my code which is also a very nice feature. So, there you have it. That's the basics of the factory pattern, which as I said before are probably one of the most fundamental and most used design patterns in software development.







