Design Patterns in Swift: Abstract Factory
Dejan Agostini

Abstract factory is one of the creational design patterns. You probably encountered it in your development without realising. Here we'll cover the swift version of the text-book version of the design pattern and say a few words about the dependency inversion principle.
Let's see how to implement this pattern in swift.
Abstract Factory
We're all taught to code to an interface, not an implementation. And that's some really good advice. But eventually you'll have to create some objects somewhere. That's where the abstract factory pattern comes in. The purpose of the abstract factory is to abstract away object creation and centralise it in a class. This way you can keep coding to an interface, and inject your factory into the classes that need to use it. The actual definition of the abstract factory pattern from the gang of four is:Provide an interface for creating families of related or dependent objects without specifying their concrete classes.As the definition says, the abstract factory is nothing more than a protocol that we'll use on a concrete class to create objects. In our example we'll use the abstract factory to create some animal shops. This will be a simple factory, let's see it on a diagram first:
Let's see how to implement this pattern in swift.
The Code
We'll only need three protocols to implement this factory, the animal shop protocol:protocol AnimalShop {
func createDog() -> Dog?
func createCat() -> Cat?
}
This will be our factory protocol. 'Abstract' is a keyword in other languages that we don't have in swift/obj-c, the closest keyword we have would be 'protocol'. So this is our abstract factory definition. The factory will create a dog and a cat, so we need protocols for them as well:
protocol Dog {
var name: String { get }
func bark()
}protocol Cat {
var name: String { get }
func meow()
}
We'll be making three factories. For creating pets, toys, and a mock factory for out unit tests.
PetShop Factory
Let's say you're creating a pet store, you might have a factory that looks something like this:class PetShop: AnimalShop {
private let dict: [String: String]
init(dict: [String: String]) {
self.dict = dict
}
func createDog() -> Dog? {
guard let name = dict["dogName"] else {
return nil
}
return PetShopDog(name: name)
}
func createCat() -> Cat? {
guard let name = dict["catName"] else {
return nil
}
return PetShopCat(name: name)
}
}
private struct PetShopDog: Dog {
var name: String
func bark() {
print("\(name) is barking!")
}
}
private struct PetShopCat: Cat {
var name: String
func meow() {
print("\(name) doesn't care")
}
}
This factory takes in a dictionary with a dog and a cat name, and it creates your cats and dogs out of that dictionary. You probably noticed that the 'PetShopDog' and 'PetShopCat' structs are private and accessible only to the 'PetShop' factory. Obviously, in these classes you would implement your real objects with their custom behaviour. Here we just have some cats and some dogs.
ToyShop Factory
Pet shop is not the only shop that can sell cats and dogs. We can have totally different types of objects being created that are still considered to be cats and dogs. Let's create a simple toy shop factory:class ToyShop: AnimalShop {
private let inventory: [String: Any]
init(inventory: [String: Any]) {
self.inventory = inventory
}
func createDog() -> Dog? {
guard
let dict = inventory["dog"] as? [String: String],
let name = dict["name"]
else {
return nil
}
return ToyDog(name: name)
}
func createCat() -> Cat? {
guard
let dict = inventory["cat"] as? [String: String],
let name = dict["name"]
else {
return nil
}
return ToyCat(name: name)
}
}
private struct ToyDog: Dog {
var name: String
func bark() {
print("Put some batteries in first")
}
}
private struct ToyCat: Cat {
var name: String
func meow() {
print("press my paw to meow")
}
}
Here our factory is being initialised with a different type of object, a dictionary of dictionaries. And, as you can see, the actual 'ToyDog' and 'ToyCat' implementations are different from the pet shop. A toy dog will need batteries to bark :)
MockShop Factory
If you're writing your unit tests, and I hope you are, you'll want to be able to create your cats and dogs in a controlled manner. Mock factories are ideal for this. You can inject these factories into your classes and be sure the generated objects are exactly the ones you would expect. An example of a mock factory would be:class MockShop: AnimalShop {
func createDog() -> Dog? {
return MockDog(name: "Fidisimo")
}
func createCat() -> Cat? {
return MockCat(name: "Bender")
}
}
private struct MockDog: Dog {
var name: String
func bark() {
print("bark yourself")
}
}
private struct MockCat: Cat {
var name: String
func meow() {
print("kill all humans")
}
}
This is by far the simplest factory so far, but that's exactly what you want. Why complicate things for yourself :) You would normally use this kind of factory in a unit test.
Dependency Inversion Principle
Throughout this example we actually used the dependency inversion principle. The definition of it would go something like:Depend on abstractions, don't depend on concrete classes.If you're wondering what all of this means, just look at any of the factories we created. We're implementing a factory that's creating a dog object, but we're keeping the concrete class implementation private, thus forcing the use of dependency inversion principle. All of the properties and methods that we need are in the 'Dog' protocol, and the rest of our app can use that dog object without any problems, we're just keeping the actual concrete implementation of our dog hidden. We all know that we should code to an interface, not an implementation, well, dependency inversion is just an extreme way of doing that. An easy way of remembering to use it is, always use the methods in a protocol, if your methods/properties are not in the protocol, you're breaking the principle.