Factory vs Abstract Factory Design Pattern in Java
What is factory design pattern?
Java's Factory design pattern offers an interface for creating objects without specifying the precise class of object that will be created. It separates the object creation logic into a class called the factory, which is in charge of producing the appropriate objects in accordance with the inputs or conditions given.
By ensuring that the client code only depends on the factory interface and not specific classes, the factory design pattern encourages loose coupling. Since existing classes can be changed or added without affecting client code, this makes maintenance and flexibility easier.
The following elements are typically included in the Factory design pattern in Java:
- Product: The common methods that all concrete products must implement are defined by this interface or abstract class.
- Concrete Products: These are particular instances of the product class or interface. Every concrete product offers a unique implementation of the standard procedures specified in the product.
- Factory: This class is in charge of producing concrete product instances. It has a factory method that, in response to certain conditions or inputs, produces an object of the product interface or class.
For example:
Let’s take an simple example to understand and how can we implement factory design pattern in java:
// Product interface interface Shape { void draw(); } // Concrete Products class Circle implements Shape { @Override public void draw() { System.out.println("Drawing a circle."); } } class Rectangle implements Shape { @Override public void draw() { System.out.println("Drawing a rectangle."); } } // Factory class ShapeFactory { public Shape createShape(String shapeType) { if (shapeType.equalsIgnoreCase("circle")) { return new Circle(); } else if (shapeType.equalsIgnoreCase("rectangle")) { return new Rectangle(); } return null; } } // Client code public class Main { public static void main(String[] args) { ShapeFactory factory = new ShapeFactory(); Shape circle = factory.createShape("circle"); circle.draw(); // Output: Drawing a circle. Shape rectangle = factory.createShape("rectangle"); rectangle.draw(); // Output: Drawing a rectangle. } }
Output:
Drawing a circle. Drawing a rectangle.
Explanation:
In this illustration, the ShapeFactory serves as the factory class in charge of producing the necessary shapes (Circle and Rectangle) in response to the input.
The client code does not need to be aware of the specific implementations of the shapes; it only interacts with the factory interface (Shape).
This makes it simple to add new shapes to the system because all that is needed is to implement the Shape interface and update the factory class.
Advantage of Factory design pattern in java
There are several advantages of factory design pattern in java some are as follows:
- Loose coupling: The Factory pattern encourages loose coupling between the client code and the concrete classes. By only relying on the factory interface, the client code minimises reliance on particular implementations. As a result, replacing or altering the concrete classes is simpler and has no impact on the client code.
- Encapsulation: The factory class contains an encapsulation of the object creation logic. The creation code is centralised in this way, which facilitates management and maintenance. Future modifications to the creation logic can be made in a single location.
- Abstraction: The factory interface offers an abstraction that shields the client code from the difficulties of object creation. Clients can rely on the factory interface to create the necessary objects with just a little bit of knowledge on their part.
- Reusable Code: The Factory pattern encourages reusable code. Many client classes can create objects by using the factory class. As a result, there is no longer a need for redundant object creation code throughout the system.
Disadvantage of Factory design pattern in java
There are several disadvantages of factory design pattern in java some are as follows:
- Added Complexity: The Factory pattern, especially for straightforward scenarios, can make the codebase more complex. Interfaces, concrete classes, and the factory class itself must all be defined. The extra complexity might not be necessary for straightforward object creation or small projects.
- Dependency on the Factory: When using the Factory pattern, the factory class is dependent upon the client code. The factory class can introduce problems and have an impact on the entire system if it is not properly implemented or maintained.
- Limited Flexibility: The Factory pattern works best when the range of potential object types is predetermined. Modifying the factory class might be necessary to accommodate the addition of new object types, which could necessitate multiple code changes. If the system demands dynamic object creation based on runtime circumstances, this may be restrictive.
- Increased Code Volume: The Factory pattern must be implemented by defining a number of classes, including the factory class, the concrete classes, and the product interface. If not managed properly, this can increase the project's overall code volume, which could have an impact on readability and maintainability.
What is abstract factory design pattern in java?
Java's Abstract Factory design pattern offers an interface for building families of connected or interdependent objects without specifying their concrete classes. It allows the creation of numerous related objects and is an extension of the Factory pattern.
When there are several families of related products and the client code needs to create objects from one of these families without being aware of the specific classes involved, the Abstract Factory pattern can be helpful. Each concrete factory class implements this interface to produce the corresponding family of products. It provides an abstract factory interface that declares a set of creation methods for each type of product.
The following elements are typically included in the Abstract Factory pattern in Java:
- Abstract factory: The creation methods for each type of product are declared in the interface or abstract class known as the abstract factory. It offers a standard interface for building the connected objects.
- Concrete Factories: The concrete classes that carry out the abstract factory interface are known as concrete factories. The specific family of related products is produced by each concrete factory.
- Abstract product: All products within a family must implement the common methods defined by the interfaces or abstract classes known as abstract products.
- Concrete Products: These are the particular applications of the classes or interfaces for abstract products. The common methods specified in the abstract product are implemented differently in each concrete product.
For example:
Let’s take a simple example to understand and how can we implement abstract factory design pattern in java:
// Abstract Product A interface Button { void render(); } // Concrete Product A1 class WindowsButton implements Button { @Override public void render() { System.out.println("Rendering a Windows button."); } } // Concrete Product A2 class MacOSButton implements Button { @Override public void render() { System.out.println("Rendering a macOS button."); } } // Abstract Product B interface Checkbox { void render(); } // Concrete Product B1 class WindowsCheckbox implements Checkbox { @Override public void render() { System.out.println("Rendering a Windows checkbox."); } } // Concrete Product B2 class MacOSCheckbox implements Checkbox { @Override public void render() { System.out.println("Rendering a macOS checkbox."); } } // Abstract Factory interface GUIFactory { Button createButton(); Checkbox createCheckbox(); } // Concrete Factories class WindowsFactory implements GUIFactory { @Override public Button createButton() { return new WindowsButton(); } @Override public Checkbox createCheckbox() { return new WindowsCheckbox(); } } class MacOSFactory implements GUIFactory { @Override public Button createButton() { return new MacOSButton(); } @Override public Checkbox createCheckbox() { return new MacOSCheckbox(); } } // Client code public class Main { public static void main(String[] args) { GUIFactory factory; // Create a Windows GUI factory = new WindowsFactory(); Button windowsButton = factory.createButton(); Checkbox windowsCheckbox = factory.createCheckbox(); windowsButton.render(); // Output: Rendering a Windows button. windowsCheckbox.render(); // Output: Rendering a Windows checkbox. // Create a macOS GUI factory = new MacOSFactory(); Button macOSButton = factory.createButton(); Checkbox macOSCheckbox = factory.createCheckbox(); macOSButton.render(); // Output: Rendering a macOS button. macOSCheckbox.render(); // Output: Rendering a macOS checkbox. } }
Output:
Rendering a Windows button. Rendering a Windows checkbox. Rendering a macOS button. Rendering a macOS checkbox
Advantages of Abstract factory design pattern
In Java, the Abstract Factory design pattern has a number of benefits. Let's talk about a few of them:
- Encapsulation of object creation: The Abstract Factory pattern encapsulates object creation by grouping related objects into a single interface or abstract class. By clearly separating the client code from the object creation logic, this encourages a more modular and maintainable design.
- Loose Coupling: A loose coupling is encouraged between the client code and the concrete classes by the Abstract Factory pattern. Instead of specific product classes, the client code depends on the abstract factory interface or class. As a result, there is no need to modify the client code in order for it to function with any concrete factory implementation.
- Flexibility and extensibility: The Abstract Factory pattern offers an extensible means of constructing families of related objects. Without changing the current client code, new product families can be added by introducing fresh concrete factory classes. Due to its high extensibility and adaptability to shifting requirements.
- Adherence to the Open/Closed principle: The Open/Closed Principle states that software entities (such as classes, modules, functions, etc.) should be open for extension but closed for modification. The Abstract Factory pattern abides by this principle. With the Abstract Factory pattern, new product types can be added without changing existing code by adding new concrete factories. As a result, there is less chance of adding bugs to the existing codebase.