Search code examples
scalainheritancefactorycompositionfactory-pattern

Abstract factory pattern with constructor arguments


I have the following two ways to use the Abstract Factory pattern

Approach 1

abstract class Dough {
 def getDoughType: String
}

abstract class Sauce {
 def getSauceType: String
}

abstract class AbstractIngredientsFactory {
 def createDough: Dough
 def createSauce: Sauce
}

class ThinDough extends Dough {
  def getDoughType: String = "Thin Dough !!!"
}

class RedSauce extends Sauce {
  def getSauceType: String = "Red Sauce !!!"
}

class ChicagoStoreIngredientsFactory extends AbstractIngredientsFactory {
  def createDough: Dough = new ThinDough
  def createSauce: Sauce = new RedSauce
}

Approach 2

 //no longer seems like a factory
 case class IngredientsFactory(dough: Dough, sauce: Sauce)

 // concrete instance
 val chicagoIngrediendtsFactory = new IngredientsFactory(new ThinDough, new RedSauce)

Approach 2 though no longer resembles a standard factory, it seems to serve the same purpose of encapsulating specific ingredients to be used by a specific store. But approach 2 depends on composition and I don't need to create implementations for each region.

Is approach 2 an anti-pattern ?


Solution

  • Approach 2 is not the factory pattern, but that does not make it an anti-pattern. IngredientsFactory does not create anything, is just a container and could be called Recipe.

    The key difference is that approach 1 generates the ingredients inside the factory, whereas approach 2 injects the ingredients from the outside. Approach 1 allows the Chicago store to use a secret recipe for generating ingredients whereas approach 2 requires the Chicago store to let everyone know what the ingredients are.

    The choice depends on the application, but neither is right or wrong.


    Also note that this code in approach 1 won't compile:

    def createDough: Dough = new ThinDough
    def createSauce: Sauce = new RedSauce
    

    It should be

    val createDough: Dough = ThinDough
    val createSauce: Sauce = RedSauce