Abstract Factory is a pattern that allow you to create families of object that conform to a common protocol.

This patterns has three main components: the factory, the product and a client.

Factory:

  1. Factory protocol: Declares an interface that allows to create abstract objects.
  2. Concrete factory (class or struct): Implements the operations to create abstract objects.

Product:

  1. Product protocol: Declares an interface that defines a product object.
  2. Concrete product (class or struct): Implements the AbstractProduct interface.

Client:

  1. Client (class or struct): Uses only interfaces declared by Factory protocol and Product protocol.

Implementation

This example illustrates the structure of the Abstract Factory design pattern.

Products

We create a Product protocol that defines a single product. And then we add the concrete classes that implements the Product protocol.

// Products

protocol Car {

func drive()

func canBeDriven(by driver: Driver) -> Bool

}

class ToyotaCar: Car {

func drive() {

print("Start drive Toyota")

}

func canBeDriven(by driver: Driver) -> Bool {

if driver is ProfessionalDriver {

return true

} else {

return false

}

}

}

class LamborghiniCar: Car {

func drive() {

print("Start drive Lamborghini")

}

func canBeDriven(by driver: Driver) -> Bool {

if driver is ProfessionalDriver {

return true

} else {

return false

}

}

}

protocol Driver {

var name: String { get set }

var surname: String { get set }

func whoAmI()

}

class ProfessionalDriver: Driver {

var name: String

var surname: String

init(name: String, surname: String) {

self.name = name

self.surname = surname

}

func whoAmI() {

print("I am a professional driver.")

}

}

class NewbieDriver: Driver {

var name: String

var surname: String

init(name: String, surname: String) {

self.name = name

self.surname = surname

}

func whoAmI() {

print("I am a newbie driver.")

}

}

Factories

We create a Factory protocol that defines an interface for creating all distinct products. And then we add the concrete classes that implements the Factory protocol.

// Factories

protocol Factory {

func hireDriver() -> Driver

func buildCar() -> Car

}

class ToyotaFactory: Factory {

func hireDriver() -> Driver {

ProfessionalDriver(name: "Fernando", surname: "Alonso")

}

func buildCar() -> Car {

ToyotaCar()

}

}

class LamborghiniFactory: Factory {

func hireDriver() -> Driver {

NewbieDriver(name: "Jhon", surname: "Smith")

}

func buildCar() -> Car {

LamborghiniCar()

}

}

Client

Here we create the client that calls the creation methods of a factory object instead of creating products directly with a constructor call.

class Client {

let factory: Factory

var driverName: String {

let driver = self.hireDriver()

return "\(driver.name) \(driver.surname)"

}

// Inits

init(factory: Factory) {

self.factory = factory

}

// Methods

func buildCar() -> Car {

self.factory.buildCar()

}

func hireDriver() -> Driver {

self.factory.hireDriver()

}

func canBeDriven() -> Bool {

self.buildCar().canBeDriven(by: hireDriver())

}

}

Usage

Now we can instanciate the client providing a factory.

Conclusion

PROS

  • Isolation of concrete classes. It helps to control the classes of objects created. Because a factory encapsulates the responsibility and process of creating objects and isolates clients from concrete classes.
  • Objects of the same family can be easily interchanged. Each product of the same class can be swapped since they all conform to the same protocol.
  • Promotes consistency between objects of the same family. Each object of the same family has equal methods and property defined in the implemented protocol.

CONS

  • Supporting new product types. Since the Factory protocol defines all the various types of products that can be instantiated, adding a family means changing the factory interface. This change affects the concrete factories and all the subclasses, making the operation laborious.

Thank you for reading

What are you thoughts about this? Tweet me @franceleonidev and share your opinion.

Source link