Abstract Factory in Java
Abstract Factory is a creational design pattern that provides a way to create families of related or dependent objects without specifying their concrete classes. The abstract factory pattern is used to provide a client with a set of related or dependant objects. The "factory" object has the responsibility of providing creation services for the entire platform. The Abstract Factory pattern is particularly useful when a system should be independent from how its products are created, composed, and represented. This helps you to change the products that a system uses without changing the code that uses those products. It is also used when you want to provide a library of objects to clients, but don’t want to reveal the concrete classes that the library uses to create these objects. According to the Abstract Factory Pattern, you should only construct an abstract class or interface to create families of related (or dependent) items, not their specific concrete subclasses. In other words, Abstract Factory enables a class to return a class factory. Thus, the Abstract Factory Pattern is one level above the Factory Pattern for this reason.
Advantages of Abstract Factory:
- Concrete (implementation) classes are separated from client code via the abstract factory pattern.
- Exchange of object families is made simpler.
- It encourages object consistency.
Abstract factory pattern used:
- when the system must be autonomous of the creation, composition, and representation of its objects.
- This restriction must be upheld when a group of related objects must be utilised together.
- when you want to offer a library of objects that just displays interfaces and hides implementations.
- when a specific family of items from a number of families must be configured in the system.
In Java, the Abstract Factory pattern can be implemented using interfaces, abstract classes, and concrete classes. The abstract factory interface declares a set of methods that return different abstract products. These products are related by a common theme or concept. Concrete factories are the classes that implement these methods to return the concrete products that belong to a specific theme or concept. The client uses only the abstract factory interface, thereby creating the products, but not the concrete classes that implement them. For example, consider an application that needs to display GUI components on multiple platforms, such as Windows, Linux, and Mac. The Abstract Factory pattern can be used to create the appropriate GUI components for each platform. In this scenario, the abstract factory interface would declare methods to create buttons, text fields, and other GUI components, and concrete factories would implement these methods to return the platform-specific GUI components. The client code would use only the abstract factory interface, and would not need to be aware of the concrete classes that implement the GUI components. One of the key benefits of the abstract factory pattern is that it makes it easier to change the implementation of objects without affecting the client code. For example, if a new type of object is needed, the concrete class that implements the abstract factory can be updated to include the new object, without affecting the client code. The Abstract Factory pattern is a great way to encapsulate object creation and provide a clean, flexible, and easy-to-use API. It also promotes loose coupling between the objects in a system and can be used to create objects that belong to different families or have different behaviors. Additionally, the Abstract Factory pattern can be easily extended to support new types of products, simply by adding new concrete factories and concrete products to the system. In an abstract factory pattern, an abstract factory class defines a set of methods to create objects from a common interface. The concrete classes that implement the abstract factory define the methods to create the specific objects. The client code interacts with the abstract factory to create objects, and the objects are returned through the common interface. In conclusion, the Abstract Factory pattern is a powerful creational design pattern that provides a flexible and scalable solution for creating families of related or dependent objects. By decoupling the concrete classes that create objects from the client code that uses them, the
Abstract Factory pattern makes it easy to change the products that a system uses without changing the code that uses those products. Here's an implementation of the Abstract Factory pattern in Java:
Program:
// File name: FactoryProducer.java
interface Shape {
void draw();
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing Circle");
}
}
class Square implements Shape {
@Override
public void draw() {
System.out.println("Drawing Square");
}
}
interface Color {
void fill();
}
class Red implements Color {
@Override
public void fill() {
System.out.println("Filling Red");
}
}
class Green implements Color {
@Override
public void fill() {
System.out.println("Filling Green");
}
}
abstract class AbstractFactory {
abstract Shape getShape(String shapeType);
abstract Color getColor(String colorType);
}
class ShapeFactory extends AbstractFactory {
@Override
Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
@Override
Color getColor(String colorType) {
return null;
}
}
class ColorFactory extends AbstractFactory {
@Override
Shape getShape(String shapeType) {
return null;
}
@Override
Color getColor(String colorType) {
if (colorType == null) {
return null;
}
if (colorType.equalsIgnoreCase("RED")) {
return new Red();
} else if (colorType.equalsIgnoreCase("GREEN")) {
return new Green();
}return null;
}
}class FactoryProducer {
static AbstractFactory getFactory(String choice) {
if (choice.equalsIgnoreCase("SHAPE")) {
return new ShapeFactory();
} else if (choice.equalsIgnoreCase("COLOR")) {
return new ColorFactory();
}return null;
}
}
You can use the above code in the following way to get the objects of the desired type:
Program: Example
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
Shape shape1 = shapeFactory.getShape("CIRCLE");
shape1.draw();
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
Color color1 = colorFactory.getColor("RED");
color1.fill();
The Abstract Factory design pattern is a creational pattern that provides an interface for creating families of related objects without specifying the concrete classes of the objects. It is used to create objects that belong to a related group or family, while keeping the client code decoupled from the specifics of the objects it creates. In Java, the Abstract Factory pattern is implemented by defining an abstract factory class that provides an interface for creating each of the products. The abstract factory class defines methods for creating the products, but it does not provide the actual implementation for creating the products. The implementation is left to concrete factory classes, which are subclasses of the abstract factory class. The concrete factory classes provide the implementation for creating the products. For example, if you have two product families, Shapes and Colors, you would create concrete factory classes for each product family. The ShapeFactory class would provide the implementation for creating Circle, Square, and Triangle objects, and the ColorFactory class would provide the implementation for creating Red, Green, and Blue objects.
To use the Abstract Factory pattern, you would create an instance of the appropriate concrete factory class and use it to create the objects you need. For example, to create a Circle object, you would do the following:
Program:
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
Shape shape = shapeFactory.getShape("CIRCLE");
shape.draw();
The FactoryProducer class is a helper class that returns the appropriate concrete factory class based on the type of object you want to create. In this example, it returns the ShapeFactory class. The advantages of using the Abstract Factory pattern in Java include:
- Loose coupling: The client code is decoupled from the specifics of the objects it creates, making it easy to change the objects without changing the client code.
- Flexibility: The Abstract Factory pattern provides a flexible and scalable way to manage the creation of objects, making it a valuable tool for any software developer to have in their toolbox.
- Reusability: The concrete factory classes can be reused in other projects, making it easier to create new objects.
The disadvantages of using the Abstract Factory pattern in Java include:
- Complexity: The pattern can be complex to implement and understand, especially for inexperienced developers.
- Performance overhead: The Abstract Factory pattern can have a performance overhead, especially when creating large numbers of objects.
In conclusion, the Abstract Factory pattern is a useful design pattern for creating objects that belong to a related group or family. It provides a flexible and scalable way to manage the creation of objects, while keeping the client code decoupled from the specifics of the objects it creates. When used correctly, the Abstract Factory pattern can make your code more maintainable and reusable, making it a valuable tool for any software developer to have in their toolbox.