Abstract Factory Pattern

Abstract Factory Pattern says that just define an interface or abstract class for creating families of related (or dependent) objects but without specifying their concrete sub-classes.

Abstract Factory pattern is almost similar to Factory Pattern is considered as another layer of abstraction over factory pattern. Abstract Factory patterns work around a super-factory which creates other factories.

When to use Abstract Factory Pattern :

  • there are number of products fall into families
  • the families of products need to stay together, but only one subset of families can be used at a particular time
  • the internal implementation is hidden and needs to expose via an interface
  • the client does not need internal implementations and details of object creations
  • the system needs more modularity and abstraction to separate the functionalities Standard Class Diagram

// Java Program to demonstrate the
// working of Abstract Factory Pattern

enum class CarType {
    MICRO, MINI, LUXURY
}

abstract class Car(model: CarType, location: Location) {

    var model: CarType? = null
    var location: Location? = null

    init {
        this.model = model
        this.location = location
    }

    abstract fun construct()

    override fun toString(): String {
        return "CarModel - $model located in $location"
    }
}

class LuxuryCar(location: Location) : Car(CarType.LUXURY, location) {
    init {
        construct()
    }

     override fun construct() {
        println("Connecting to luxury car")
    }
}

class MicroCar(location: Location) : Car(CarType.MICRO, location) {
    init {
        construct()
    }

    override fun construct() {
        println("Connecting to Micro Car ")
    }
}

class MiniCar(location: Location) : Car(CarType.MINI, location) {
    init {
        construct()
    }

    override fun construct() {
        println("Connecting to Mini car")
    }
}

enum class Location {
    DEFAULT, USA, INDIA
}

class INDIACarFactory {
    fun buildCar(model: CarType): Car? {
        var car: Car? = null
        when (model) {
            CarType.MICRO -> car = MicroCar(Location.INDIA)

            CarType.MINI -> car = MiniCar(Location.INDIA)

            CarType.LUXURY -> car = LuxuryCar(Location.INDIA)

            else -> {
            }
        }
        return car
    }
}

fun buildCar(model: CarType): Car? {
    var car: Car? = null
    when (model) {
        CarType.MICRO -> car = MicroCar(Location.DEFAULT)

        CarType.MINI -> car = MiniCar(Location.DEFAULT)

        CarType.LUXURY -> car = LuxuryCar(Location.DEFAULT)

        else -> {
        }
    }
    return car
}



internal object USACarFactory {
    fun buildCar(model: CarType): Car? {
        var car: Car? = null
        when (model) {
            CarType.MICRO -> car = MicroCar(Location.USA)

            CarType.MINI -> car = MiniCar(Location.USA)

            CarType.LUXURY -> car = LuxuryCar(Location.USA)

            else -> {
            }
        }
        return car
    }
}


class CarFactory {
    fun buildCar(type: CarType): Car? {
        var car: Car? = null
        // We can add any GPS Function here which
        // read location property somewhere from configuration
        // and use location specific car factory
        // Currently I'm just using INDIA as Location
        val location = Location.INDIA

        when (location) {
            Location.USA -> car = USACarFactory.buildCar(type)

            Location.INDIA -> car = INDIACarFactory().buildCar(type)

            else -> car = buildCar(type)
        }

        return car

    }
}

fun main(args: Array<String>) {
    println(CarFactory().buildCar(CarType.MICRO))
    println(CarFactory().buildCar(CarType.MINI))
    println(CarFactory().buildCar(CarType.LUXURY))
}			

Output of the Abstract factory pattern in kotlin


Connecting to Micro Car 
CarModel - MICRO located in INDIA
Connecting to Mini car
CarModel - MINI located in INDIA
Connecting to luxury car
CarModel - LUXURY located in INDIA			

Advantages of Abstract Factory Pattern :

  • Enabled error-free management of families of related products
  • Concrete factories work independently of each other, enabling easy product family exchange and handling at run-time
  • Improves consistency among related products
  • Many objects can be added or changed dynamically during the run-time
  • Divides the responsibilities among multiple concrete factory classes
  • Can add more products to families and concrete factories will take care of those product creations
  • Enforce encapsulation and modularization through concrete factories and abstract interfaces
  • The client program is independent of the internal object construction mechanism
  • Abstract factory avoids long conditional logic as in factory pattern

Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions