The Abstract Factory Pattern, also known as the Kit pattern, is a design pattern that abstracts the factory of classes to allow for the creation of product class clusters, rather than just being responsible for creating instances of a certain type of product. The pattern provides an interface for creating a series of related or interdependent objects without specifying their concrete classes. It belongs to the category of object creation patterns.
In the Factory Method Pattern, a specific factory is responsible for producing specific products, with each concrete factory corresponding to a particular product. The factory method also has uniqueness, typically with only one factory method or a group of overloaded factory methods within a specific factory. However, there are cases when a factory needs to provide multiple product objects instead of just a single product object. When the system's factory needs to produce specific products that are not just simple objects, but multiple objects belonging to different product hierarchy levels and types, the Abstract Factory Pattern is used.
The main distinction between the Abstract Factory Pattern and the Factory Method Pattern is that the Factory Method Pattern addresses a single product hierarchy, while the Abstract Factory Pattern needs to handle multiple product hierarchies. A factory hierarchy can be responsible for creating objects from multiple different product hierarchies. When a factory hierarchy can create all objects belonging to a product family in different product hierarchies, the Abstract Factory Pattern is simpler and more efficient than the Factory Method Pattern.
The Abstract Factory Pattern isolates the generation of specific classes, allowing the client to be unaware of what is being created. This isolation makes it relatively easy to switch to a different concrete factory. Since all concrete factories implement the common interfaces defined in the abstract factory, changing the concrete factory instance can to some extent change the behavior of the entire software system. Additionally, applying the Abstract Factory Pattern can achieve the design goal of high cohesion and low coupling, making it widely applicable.
When multiple objects in a product family are designed to work together, it ensures that the client always uses objects from the same product family. This is a very practical design pattern for software systems that need to determine their behavior based on the current environment.
Adding new concrete factories and product families is convenient and does not require modifying the existing system, adhering to the open-closed principle.
Adding new product objects can be difficult because extending the abstract factory to produce new types of products would involve modifying the interface in the abstract factory role, requiring changes to the abstract factory role and all its subclasses, which is obviously inconvenient.
The bias of the open-closed principle: adding new factories and product families is easy, but adding new product hierarchies is troublesome.
classShape{// Base class for shapesdraw(){ console.log(this.shape);}}classRectangleextendsShape{// Rectangleconstructor(){super();this.shape ="Rectangle";}}classSquareextendsShape{// Squareconstructor(){super();this.shape ="Square";}}classCircleextendsShape{// Circleconstructor(){super();this.shape ="Circle";}}classColor{// Base class for colorsfill(){ console.log(this.color);}}classRedextendsColor{// Redconstructor(){super();this.color ="Red";}}classGreenextendsColor{// Greenconstructor(){super();this.color ="Green";}}classBlueextendsColor{// Blueconstructor(){super();this.color ="Blue";}}classFactory{// Base class for factories mimicking abstract methodsgetShape(){thrownewError("Abstract method cannot be called");}getColor(){thrownewError("Abstract method cannot be called");}}
classShapeFactoryextendsFactory{// Shape FactorygetShape(shape){switch(shape.toLowerCase()){case"rectangle":returnnewRectangle();case"square":returnnewSquare();case"circle":returnnewCircle();default:thrownewError("Parameter Error");}}getColor(){returnnull;}}classColorFactoryextendsFactory{// Color FactorygetShape(){returnnull;}getColor(color){switch(color.toLowerCase()){case"red":returnnewRed();case"green":returnnewGreen();case"blue":returnnewBlue();default:thrownewError("Parameter Error");}}}classFactoryGenerator{// Factory Generator Class: Get factory by passing shape or colorstaticgetFactory(choice){ choice = choice.toLowerCase();if(choice ==="shape"){returnnewShapeFactory();}elseif(choice ==="color"){returnnewColorFactory();}thrownewError("Parameter Error");}}(function(){var shapeFactory = FactoryGenerator.getFactory("shape");var colorFactory = FactoryGenerator.getFactory("color"); shapeFactory.getShape("rectangle").draw(); shapeFactory.getShape("square").draw(); shapeFactory.getShape("circle").draw(); colorFactory.getColor("red").fill(); colorFactory.getColor("green").fill(); colorFactory.getColor("blue").fill();})();