The factory pattern is a common good practice to create objects that mix both dependencies and parametrization. Factories are also very suited to “hide” dependencies of the created objects, which the creator do not have to care about. Factories are usually a lot of boilerplate code, prone to tedius repetition and human error. Typhoon Factory Providers aims to eliminate some of that boilerplate by creating the factory implementation from the interface definition and a little bit of glue code. # The problem Imagine having two view controllers with the following interfaces: ```obj-c @interface ParentViewController - (instancetype)initWithUsersService:(UsersService *)usersService; // dependency @end @interface ChildViewController - (instancetype)initWithUsersService:(UsersService *)usersService // dependency photoService:(PhotoService *)photoService // dependency user:(User *)user; @end ``` The `ParentViewController` will be the typical list of users, and the `ChildViewController` will show the details for the user passed as argument. From those two interfaces it is obvious that `ParentViewController` is missing a piece to create instances of `ChildViewController`: the dependency of `PhotoService`. One solution will be making the `ParentViewController` also depend on `PhotoService`, but that is an artificial dependency and presents a lot of problems (like the explosion of dependencies in early objects of the dependency graph, for example). # The solution The best solution is to not let `ParentViewController` create the `ChildViewController` instances directly, but to move that reponsability aside to an specialized type: the `ChildViewControllerFactory`. This is not a new dependency of `ParentViewController`: it is one that it already had, because we were using the name `ChildViewController` directly in the implementation of `ParentViewController`, which was a hidden dependency, and a very strong one, indeed. So, our interfaces will end like the following code: ```obj-c @interface ParentViewController : UIViewController - (instancetype)initWithUsersService:(UsersService *)usersService // dependency childViewControllerFactory:(ChildViewControllerFactory *)childViewControllerFactory; // dependency @end // Notice that the child have not changed. @interface ChildViewController : UIViewController - (instancetype)initWithUsersService:(UsersService *)usersService // dependency photoService:(PhotoService *)photoService // dependency user:(User *)user; @end @interface ChildViewControllerFactory : NSObject - (instancetype)initWithUsersService:(UsersService *)usersService // dependency photoService:(PhotoService *)photoService; // dependency - (ChildViewController *)childViewControllerWithUser:(User *)user; @end ``` The `ChildViewControllerFactory` will be created by the assembly, so the `ParentViewController` do not know anything else about it but how to create the `ChildViewController` instances from it. If the dependencies for the `ChildViewController` change, the only class that needs to be modified is the `ChildViewControllerFactory`, while `ParentViewController` keeps using the factory in the same way. # Creating factories “by hand” Creating a factory by hand involves a little bit of code. The interface for our example factory can be seen in the previous block of code. The implementation will be something like the following: ```obj-c @implementation ChildViewControllerFactory { @private UsersService *_usersService; PhotoService *_photoService; } - (instancetype)initWithUsersService:(UsersService *)usersService photoService:(PhotoService *)photoService { self = [super init]; if (self) { _usersService = usersService; _photoService = photoService; } return self; } - (ChildViewController *)childViewControllerWithUser:(User *)user { return [[ChildViewController alloc] initWithUsersService:_usersService photoService:_photoService user:user]; } @end ``` It is not a great number of lines of code, but it is still a lot of code. Specially if you think that this is one of the many factories your app will eventually have. Also, if any of the dependencies disappear, or a new one appear, you will have to change those initializers and also your Typhoon assembly definition. Computers should help us to repeat tedious tasks, right? # Creating factories using Typhoon Factory Provider Using `TyphoonFactoryProvider` will decrease the code you need to type to create a factory, and will keep the code grouped, so changes are easier. The first change is that your factories are no longer classes, but protocols. Using a protocol allows you to not write the concrete implementation, leaving that task to Typhoon. Following the previous examples, we will need to change some classes a little bit: ```obj-c @interface ParentViewController : UIViewController - (instancetype)initWithUsersService:(UsersService *)usersService // dependency childViewControllerFactory:(id)childViewControllerFactory; // dependency @end // ChildViewController do not change @protocol ChildViewControllerFactory @property (nonatomic, strong, readonly) UsersService *usersService; // dependency @property (nonatomic, strong, readonly) PhotoService *photoService; // dependency - (ChildViewController *)childViewControllerWithUser:(User *)user; @end ``` You must follow some rules when defining protocols to be used with `TyphoonFactoryProvider`: 1. The dependencies MUST be the only properties defined in the protocol. 1. The dependencies MUST be object instances. No scalar types are supported at the moment. 1. The dependency properties MUST be `readonly`. 1. The rest of the methods will be considered factory methods. You MUST NOT have any other method in the factory. 1. The method argument CAN be both object instances and scalar types. Those rules may seem restrictive, but most of the factories you need will fit perfectly. You can always have a factory or two in your app that cannot follow those rules, but you are free to provide your own implementation for those two factories, while the rest of them use `TyphoonFactoryProvider`. The last step is using `TyphoonFactoryProvider` in your assembly: ```obj-c #import "ChildViewController.h" #import "ChildViewControllerFactory.h" // ... - (id)childViewControllerFactory { return [TyphoonFactoryProvider withProtocol:@protocol(ChildViewControllerFactory) dependencies:^(TyphoonDefinition *definition) { // Use any kind of injectProperty method here. [definition injectProperty:@selector(usersService)]; [definition injectProperty:@selector(photoService)]; } factory:^id (id factory, User *user) { return [[ChildViewController alloc] initWithUsersService:factory.usersService photoService:factory.photoService user:user]; }]; } ``` The dependencies block is a standard `TyphoonDefinitionBlock`, so you can configure the `TyphoonDefinition` as any other from your assembly. The factory block is a little bit special: it must return `id` (you can write your class name here, but it is not necessary), and it receives as arguments the same arguments as your protocol method, in the same order and with the same type, but with an extra argument at the start which is the factory instance itself. This argument allow you to have access to the dependency properties (see `factory.usersService` used as first argument for the initializer). The rest of the arguments can be used directly. If you ever decide to stop using Typhoon, you do not need to change anything in your own classes, but you will need to create the concrete implementations of the factories Typhoon was creating for you. Using `TyphoonFactoryProvider` your code is not tied to Typhoon, since the factory was just an interface, and your code will keep working without changes as before. # More advanced factories `TyphoonFactoryProvider` can be also used to create a little bit more complex factories. Imagine we have the following model and factory: ```obj-c extern double const PizzaSmallRadius; extern double const PizzaMediumRadius; extern double const PizzaLargeRadius; @interface Pizza : NSObject - (instancetype)initWithCreditService:(CreditService *)creditService radius:(double)radius ingredients:(NSArray *)ingredients; @end @protocol PizzaFactory @property (nonatomic, strong, readonly) CreditService *creditService; - (Pizza *)pizzaWithRadius:(double)radius ingredients:(NSArray *)ingrendients; - (Pizza *)smallPizzaWithIngredients:(NSArray *)ingredients; - (Pizza *)mediumPizzaWithIngredients:(NSArray *)ingredients; - (Pizza *)largePizzaWithIngredients:(NSArray *)ingredients; @end ``` How will one use `TyphoonFactoryProvider` for such protocol? The truth is that the method shown above is just a shortcut for the real method. You can use the shortcut whenever your factory has only one factory method (which will be a large number of your factories, probably). You will need the longer method only if you have several factory methods. ```obj-c - (id)pizzaFactory { return [TyphoonFactoryProvider withProtocol:@protocol(PizzaFactory) dependencies:^(TyphoonDefinition *definition) { [definition injectProperty:@selector(creditService)]; } factories:^(TyphoonAssistedFactoryDefinition *definition) { [definition factoryMethod:@selector(pizzaWithRadius:ingredients:) body:^id (id factory, double radius, NSArray *ingredients) { return [[Pizza alloc] initWithCreditService:factory.creditService radius:radius ingredients:ingredients]; }]; [definition factoryMethod:@selector(smallPizzaWithIngredients:) body:^id (id factory, NSArray *ingredients) { return [[Pizza alloc] initWithCreditService:factory.creditService radius:PizzaSmallRadius ingredients:ingredients]; }]; [definition factoryMethod:@selector(mediumPizzaWithIngredients:) body:^id (id factory, NSArray *ingredients) { return [[Pizza alloc] initWithCreditService:factory.creditService radius:PizzaMediumRadius ingredients:ingredients]; }]; [definition factoryMethod:@selector(largePizzaWithIngredients:) body:^id (id factory, NSArray *ingredients) { return [[Pizza alloc] initWithCreditService:factory.creditService radius:PizzaLargeRadius ingredients:ingredients]; }]; }]; } ``` The previous `factory:` block has turned into a `factories:` block. This block provides an argument which you can use to define the bodies of your different factory methods, associating selectors with body blocks using the `factoryMethod:body:` method of `TyphoonAssistedFactoryDefinition`. # Future directions `TyphoonFactoryProvider` does reduce the quantity of boilerplate code you have to type, but it does still need a lot of human-provided code to work. Ideally, all those factory method body blocks should be created automatically, but the truth is that the Objective-C runtime is, sometimes, not powerful enough. If you have any idea or suggestion how to improve the code, it will be welcome. # Known limitations You SHOULD NOT create two factories with different factory method blocks from the same protocol, not even in different assemblies. If you do so, it is undefined which one of the two implementations you will invoke.