Factory Method and Abstract Factory in Swift and iOS Universe

Factory Method and Abstract Factory in Swift and iOS UniverseExploring creational design patternsNikita Lazarev-ZubovBlockedUnblockFollowFollowingMay 31Photo by Fabian Grohs on UnsplashThe word factory is undoubtedly one of the most commonly used words for programmers while discussing their, or other’s, programs.

At the same time, what exactly they mean differs.

It might be a generating objects class (either polimorphic or not), a returning objects method (either static or not), or even a regular constructor.

However, not everything that generates objects can be called a factory.

Furthermore, this word can describe two different creational design patterns in Gang of Four’s arsenal — Factory Method and Abstract Factory.

I’d like to dive into the details of what they are, paying special attention to their classic implementation and understanding.

This essay is inspired by Joshua Kerievsky (head of Industrial Logic), or rather, his book “Refactoring to Patterns.

” This book was released at the turn of the century within the Martin Fowler signature series.

Fowler was the eminent author of modern programming classic “Refactoring: Improving the Design of Existing Software.

”If you haven’t read Kerievsky’s book, or haven’t heard about it, don’t hesitate to add it to your reading list.

It’s a worthy sequel to both “Refactoring” and the more classical “Design Patterns: Elements of Reusable Object-Oriented Software.

” The book, among other things, contains several dozen recipes for getting rid of different code smells through the use of design patterns.

Abstract FactoryAbstract Factory UMLIn his book, Kerievsky gives two examples of when this patter turns out useful.

Encapsulation of concrete types which are bound by a common interface.

In this case such knowledge would belong to one type, a factory.

Factory’s public API consists of method set (static or not), which returns instances of the common interface type and has meaningful names so we know which one must be called for a specific purpose.

The second one is similar to the first and in general, all the scenarios we use are more or less alike.

This is because creation of instances of one type, or a group of types, occurs in different parts of the program.

Again, factory encapsulates creational code, but it is motivated differently.

This is of particular relevance if that code is complex and isn’t limited by an initializer call.

To stay with the iOS development world, it’s rather convenient to exercise UIViewController subclasses.

Indeed, it’s one of the prevalent types in iOS software development, almost always being subclassed before usage.

Concrete class is often not important for a client code.

I’ll try to keep code examples as close as possible to classical pattern implementations from the Gang of Four’s book, although real world code can be simplified in some way.

And only deep understanding of the principles laying in the base allows one to use it more freely.

Detailed exampleSuppose our app sells vehicles and a view/presentation depends on its type .

We’ll use different UIViewController subclasses for different vehicle types.

Besides that, all vehicles differ in its state — new and used.

Thus, we have a family of types of the same group, instances of which are being created in similar places depending on a condition.

For example, user taps an item in the list — depending on the type of tapped vehicle, it’s being created differently.

View controller’s initializers have parameters values which must be passed every time.

Don’t these arguments reveal advantages of creating a factory, which would be the only type that is aware of required controller creation details?Evidently, the example is rather simple.

In the real world, introducing this factory would be overengineering.

However, one can imagine more vehicle types with more than one parameter in their initializers, and abstract factory advantages become more obvious.

Now then, let’s introduce our abstract factory interface:protocol VehicleViewControllerFactory { func makeBicycleViewController() -> UIViewController func makeScooterViewController() -> UIViewController}Brief Swift API programming guide recommends to name factory methods prefixed with “make”Gang of Four’s example is written in C++ and based on inheritance and virtual functions.

In Swift we’re closer to protocol-oriented programming techniques.

Factory interface contains only two methods, creating view controllers for bicycles and scooters.

Those methods return instances of the common parent class.

Thus, awareness’ area spread is being limited by the region where it is really necessary.

Let’s add two concrete factories which implement abstract factory interface:Thus, in our case concrete factories are responsible for vehicles in different condition, new and used.

Henceforth, necessary view controller is created like this:let factory: VehicleViewControllerFactory = NewVehicleViewControllerFactory()let vc = factory.

makeBicycleViewController()Incapsulate classes with factoryIncapsulate classes with Factory by Joshua KerievskyNow, let us consider in short the examples which are given in Kerievsky’s book.

The first one is about incapsulation of concrete types.

Remember same view controller subclasses for displaying the data on a vehicle:final class BicycleViewController: UIViewController { }final class ScooterViewController: UIViewController { }Suppose we’re dealing with a separate module, a library, for instance.

In this case the view controller classes above stays internal (by default), and factory acts as a public API.

Factory’s methods return commonly known view controller’s parent class instances.

Thereby, the knowledge about concrete types is limited by the module:public struct VehicleViewControllerFactory { func makeBicycleViewController() -> UIViewController { return BicycleViewController() } func makeScooterViewController() -> UIViewController { return ScooterViewController() }}Move creation knowledge to factoryMove creation knowledge to Factory by Joshua KerievskyThe second case describes complex initialization of an object, and Kerievsky, for the sake of code simplicity and incapsulation, offers to constrain the knowledge of the process with the factory class limits.

Assume we sell cars as well.

It’s doubtless a more complex vehicle which has many more parameters and options.

Let’s implement corresponding view controller with additional parameters of fuel type, transmission type and wheel diameter:This is how the view controller can be initialized:Or we can implement a specialized factory to handle initialization:…and use it like that:let factory = UsedCarViewControllerFactory(engineType: .

gas, transmissionType: .

manual, wheelDiameter: 17)let vc = factory.

makeCarViewController()Factory MethodFactory Method UMLThe other single-rooted pattern incapsulates knowledge about concrete types too.

It does this through polymorphism instead of hiding implementation details inside a specialized class.

Kerievsky provides examples in Java in his book and offers to use abstract classes, but swift-izens don’t know what it is.

We stand on our own, we have protocols.

The Gang of Four’s book says that this pattern is also known as Virtual Constructor, and for good reason.

In C++ we call function virtual if it’s overridden by derived classes.

However, one can’t declare constructor as virtual, and presumably, the pattern invention was caused by an attempt to simulate needed behavior.

Polymorphic creationIntroduce polymorphic creation with Factory Method by Joshua KerievskyAs a classic example of pattern’s use, let’s consider a situation when different types in the same hierarchy have similar method implementation besides an object implementation which is created inside the method.

Let’s try to improve the situation by moving the object creation outside and making similar method common by moving it one step higher in hierarchy.

Let’s get back to our vehicle view controllers:final class BicycleViewController: UIViewController { }final class ScooterViewController: UIViewController { }Now, let’s think about this view controllers presentation and declare a coordinator:protocol Coordinator { var presentingViewController: UIViewController?.{ get set } func start()}Consider these coordinator implementations:Method start() has similar implementations except for view controllers which are being created inside.

Let’s move the creation outside:protocol Coordinator { var presentingViewController: UIViewController?.{ get set } func start() func makeViewController() -> UIViewController}…and extend the protocol with default implementation for start() method:extension Coordinator { func start() { let vc = makeViewController() presentingViewController?.

present(vc, animated: true) }}Then implementations will be:ConclusionI’ve tried to highlight this rather simple topic by combining three approaches:Classic declaration of the method’s existence encouraged by the Gang of Four’s book.

Use motivation nakedly inspired by Kirievsky’s book.

Application using software engineering branch which is familiar to me.

In so doing, I tried to be as close as possible to the pattern’s textbook structure not violating contemporary iOS programming principles and using Swift language possibilities (instead of more spread C++ and Java).

Apparently, it’s hard to find a good applied example.

Most existing articles and guides contain only superficial reviews and samples reduced in comparison with classic implementations.

Hopefully, I reached my goal and you enjoyed updating or refreshing your relevant knowledge!.. More details

Leave a Reply