Factories and Protocol Composition DI

Especially on iOS it’s often necessary to create new objects like new view controllers or such things. This often cannot be avoided. This usually is solved by having the object that creates new objects also require all the dependencies of the objects it wants to create. This of course is not a great thing as changes in one class can ripple through the whole project. The protocol composition approach solves this by having the flow controllers take the whole AppDependency object so they can pass it on.

This solves the problem of having to change some classes when the dependencies of others changes. But it still is bad for testing as you can’t be sure which dependencies are actually needed, and you have no way to influence which class is instantiated. A common solution to this is injecting factory objects that hold all the necessary resources. This of course can result in rather verbose code if a whole new type is created. Luckily closures can also take the role of those factories.

While implementing this I realized that an extra object is not even necessary with the protocol composition DI. The AppDependency object itself can take the role of the factory:

protocol MakesSomething {
 func makeSomething() -> Something
}

extension AppDependency: MakesSomething {
 func makeSomething() -> Something {
 return Something(dependencies: self)
 }
}

That code is not so bad and we can avoid having dependencies on unneeded objects which is good for testing. Usage is like any other dependency:

class MyClass {
 typealias Dependencies = MakesSomething & HasOtherThing
 let dependencies: Dependencies
 
 init(dependencies: Dependencies) {
 self.dependencies = dependencies
 }
 
 func doWork() {
 let something = dependencies.makeSomething()
 something.doWhateverItIsSomethingDoes()
 }
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *