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 ?
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