The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
- Creating objects directly within the class that requires the object is inflexible
- Changing the instantiation later without chaging the class is impossible
- The created object cannot be reused
- The created object is tightly coupled with the class and it makes the class hard to test because real objects can't be replaced with mock objects.
- Encapsulate object creation in a separate (factory) object. That is, define an interface (AbstractFactory) for creating objects, and implement the interface.
- A class delegates object creation to a factory object instead of creating objects directly.
- AbstractFactory (PizzaIngredientFactory)
- declares an interface for operations that create abstract products
- ConcreteFactory (ItalianPizzaIngredientFactory, AmericanPizzaIngredientFactory)
- implements the operations to create concrete product objects
- AbstractProduct (Dough)
- declares an interface for a type of product object
- ConcreteProduct(ThinCrustDough, ThickCrustDough)
- defines a product object to be created by the corresponding concrete factory
- implements the AbstractProduct interface
TODO - Add sequence diagram
- Normally a single instance of a ConcreteFactory class is created at runtime.
- Avoids tight coupling between concrete products and code that uses them.
- Allows building families of product objects and guarantees their compatibility and consistency.
- Divides responsibilities between multiple classes.
- Increases overall code complexity by creating multiple additional classes.
- Supporting new kinds of products is difficult.
- It requires extending the AbstractFactory interface, which involves changing all of its subclasses.
Definition - AbstractFactory and ConcreteFactory
publicinterfacePizzaIngredientFactory{DoughCreateDough();}publicclassAmericanPizzaIngredientFactory:PizzaIngredientFactory{publicDoughCreateDough(){returnnewThickCrustDough();}}publicclassItalianPizzaIngredientFactory:PizzaIngredientFactory{publicDoughCreateDough(){returnnewThinCrustDough();}}Definition - AbstractProduct and ConcreteProduct
publicinterfaceDough{stringGetName();}publicclassThickCrustDough:Dough{publicstringGetName(){return"Extra thick crust dough";}}publicclassThinCrustDough:Dough{publicstringGetName(){return"Thin crust dough";}}Usage
publicclassAmericanPizzaStore:PizzaStore{// AmericanPizzaStore creates the corresponding ingriedient factory.privatePizzaIngredientFactoryingredientFactory=newAmericanPizzaIngredientFactory();protectedoverridePizzaCreatePizza(PizzaTypetype){switch(type){casePizzaType.Cheese:// the correct ingredientFactory is transferred when creating a pizzareturnnewCheesePizza(ingredientFactory);casePizzaType.Veggie:returnnewVeggiePizza(ingredientFactory);default:thrownewNotImplementedException();}}}Factory Method - AbstractFactory classes are often implemented with factory methods, but they can also be implemented using Prototype.
Singleton - A concrete factory is often a singleton.
