Creational Design Patterns provide solution to instantiate an object in the best possible way for specific situations. Following design patterns come under this category.
Abstract Factory pattern is a factory of factories. It groups the individual but related/dependent factories together without specifying their concrete classes.
An abstract factory is a factory that returns factories, don't worry about pun. Why is this layer of abstraction useful? A normal factory can be used to create sets of related objects. An abstract factory returns factories. Thus, an abstract factory is used to return factories that can be used to create sets of related objects.
Abstract factory design pattern is almost similar to factory pattern except the fact that it’s more like factory of factories. If you are familiar with factory design pattern, you will notice that we have a single Factory class that returns the different sub-classes based on the input provided and factory class uses if-else
or switch
statement to achieve this. In Abstract Factory pattern, we get rid of if-else
block and have a factory class for each sub-class and then an Abstract Factory class that will return the sub-class based on the input factory class.
Benefits:
Celerio
and a factory MarutiFactory
.For completeness, let's model the Clients interactions in a sequence diagram:
Usage of Abstract factory pattern:
Java
Create an interface for Shapes.
// file Shape.java public interface Shape { void draw(); }
Create concrete classes implementing the same interface.
// file Rectangle.java public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } } // file Square.java public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } } // file Circle.java public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }
Create an interface for Colors.
// file Color.java public interface Color { void fill(); }
Create concrete classes implementing the same interface.
// file Red.java public class Red implements Color { @Override public void fill() { System.out.println("Inside Red::fill() method."); } } // file Green.java public class Green implements Color { @Override public void fill() { System.out.println("Inside Green::fill() method."); } } // file Blue.java public class Blue implements Color { @Override public void fill() { System.out.println("Inside Blue::fill() method."); } }
Create an Abstract class to get factories for Color and Shape Objects.
// file AbstractFactory.java public abstract class AbstractFactory { abstract Color getColor(String color); abstract Shape getShape(String shape) ; }
Create Factory classes extending AbstractFactory to generate object of concrete class based on given information.
// file ShapeFactory.java public class ShapeFactory extends AbstractFactory { @Override public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); }else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); }else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } @Override Color getColor(String color) { return null; } } // file ColorFactory.java public class ColorFactory extends AbstractFactory { @Override public Shape getShape(String shapeType){ return null; } @Override Color getColor(String color) { if(color == null){ return null; } if(color.equalsIgnoreCase("RED")){ return new Red(); }else if(color.equalsIgnoreCase("GREEN")){ return new Green(); }else if(color.equalsIgnoreCase("BLUE")){ return new Blue(); } return null; } }
Create a Factory generator/producer class to get factories by passing an information such as Shape or Color
// file FactoryProducer.java public class FactoryProducer { public static AbstractFactory getFactory(String choice){ if(choice.equalsIgnoreCase("SHAPE")){ return new ShapeFactory(); }else if(choice.equalsIgnoreCase("COLOR")){ return new ColorFactory(); } return null; } }
Use the FactoryProducer to get AbstractFactory in order to get factories of concrete classes by passing an information such as type.
// file AbstractFactoryPatternDemo.java public class AbstractFactoryPatternDemo { public static void main(String[] args) { AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE"); Shape shape1 = shapeFactory.getShape("CIRCLE"); shape1.draw(); Shape shape2 = shapeFactory.getShape("RECTANGLE"); shape2.draw(); Shape shape3 = shapeFactory.getShape("SQUARE"); shape3.draw(); AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR"); Color color1 = colorFactory.getColor("RED"); color1.fill(); Color color2 = colorFactory.getColor("Green"); color2.fill(); Color color3 = colorFactory.getColor("BLUE"); color3.fill(); } }
Python 3
import abc # create an interface for Shapes class Shape(metaclass=abc.ABCMeta): @abc.abstractmethod def draw(self): pass # create an interface for Colors class Color(metaclass=abc.ABCMeta): @abc.abstractmethod def fill(self): pass # create an abstract class to get factories for Color and Shape objects class AbstractFactory(metaclass=abc.ABCMeta): @abc.abstractmethod def get_color(self): pass @abc.abstractmethod def get_shape(self): pass class Rectangle(Shape): def draw(self): print("Inside Rectangle::draw() method.") class Square(Shape): def draw(self): print("Inside Square::draw() method.") class Circle(Shape): def draw(self): print("Inside Circle::draw() method.") class Red(Color): def fill(self): print("Inside Red::fill() method.") class Green(Color): def fill(self): print("Inside Green::fill() method.") class Blue(Color): def fill(self): print("Inside Blue::fill() method.") # create Factory classes extending AbstractFactory # to generate object of concrete class based on given information. class ShapeFactory(AbstractFactory): def get_shape(self, shape_type): if shape_type == None: return None if shape_type == "CIRCLE": return Circle() elif shape_type == "RECTANGLE": return Rectangle() elif shape_type == "SQUARE": return Square() return None def get_color(self): return None class ColorFactory(AbstractFactory): def get_color(self, color_type): if color_type == None: return None if color_type == "RED": return Red() elif color_type == "GREEN": return Green() elif color_type == "BLUE": return Blue() return None def get_shape(self): return None # create a Factory generator/producer class # to get factories by passing an information such as Shape or Color class FactoryProducer: @staticmethod def get_factory(choice): if choice == "SHAPE": return ShapeFactory() elif choice == "COLOR": return ColorFactory() return None if __name__ == '__main__': shape_factory = FactoryProducer.get_factory("SHAPE") shape1 = shape_factory.get_shape("CIRCLE"); shape1.draw() shape2 = shape_factory.get_shape("RECTANGLE"); shape2.draw() shape3 = shape_factory.get_shape("SQUARE"); shape3.draw() color_factory = FactoryProducer.get_factory("COLOR"); color1 = color_factory.get_color("RED"); color1.fill() color2 = color_factory.get_color("GREEN"); color2.fill() color3 = color_factory.get_color("BLUE"); color3.fill()