Java Abstract factory pattern
Using the creational design pattern known as the Abstract Factory, it is possible to build things that have a common abstract super-type without having to define the concrete classes that will be used to produce them. It gives users a high-level interface for building object families. When a system needs to be independent of the generation, composition, and representation of the objects it creates, it uses this pattern. An interface for producing things that are members of a family of related objects is defined by the Abstract Factory pattern. The things produced by each concrete application of the abstract factory belong to a particular product family. The main difference between the Abstract Factory pattern and the Factory Method pattern is that the Factory Method defines a method for creating objects, while the Abstract Factory defines a factory object that is responsible for creating objects. The factory object is created using a factory method. The Abstract Factory pattern is often used in conjunction with other design patterns such as the Factory Method, Singleton, and Prototype patterns. A practical example of using the Abstract Factory pattern is in a program that creates objects to represent graphical user interfaces. The Abstract Factory pattern is used to create objects that belong to a family of related objects. For example, a concrete implementation of the abstract factory might create objects that represent a Windows-style user interface, while another concrete implementation might create objects that represent a Mac-style user interface. The client code uses the abstract factory to create objects, rather than creating objects directly, allowing it to be flexible and scalable. The Abstract Factory pattern has several benefits, including:
- Decoupling the client code from the concrete objects that it creates: The client code uses the abstract factory to create objects, rather than creating objects directly. This allows the client code to be flexible and scalable.
- Easy maintenance: The Abstract Factory pattern makes it easy to maintain the code, as changes to the concrete objects that are being created can be made in one place, rather than in multiple places throughout the code.
- Easy testing: The Abstract Factory pattern makes it easy to test the code, as each concrete implementation of the abstract factory can be tested separately.
Program:
// Clinet.java
// Abstract Product A
interface ProductA {
String getName();
}
// Concrete Product A1
class ProductA1 implements ProductA {
public String getName() {
return "Product A1";
}
}
// Concrete Product A2
class ProductA2 implements ProductA {
public String getName() {
return "Product A2";
}
}
// Abstract Product B
interface ProductB {
String getName();
}
// Concrete Product B1
class ProductB1 implements ProductB {
public String getName() {
return "Product B1";
}
}
// Concrete Product B2
class ProductB2 implements ProductB {
public String getName() {
return "Product B2";
}
}
// Abstract Factory
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// Concrete Factory 1
class ConcreteFactory1 implements AbstractFactory {
public ProductA createProductA() {
return new ProductA1();
}
public ProductB createProductB() {
return new ProductB1();
}
}
// Concrete Factory 2
class ConcreteFactory2 implements AbstractFactory {
public ProductA createProductA() {
return new ProductA2();
}
public ProductB createProductB() {
return new ProductB2();
}
}
// Client code
public class Client {
public static void main(String[] args) {
// Create a ConcreteFactory1
AbstractFactory factory1 = new ConcreteFactory1();
// Use factory1 to create a ProductA1 and a ProductB1
ProductA productA1 = factory1.createProductA();
ProductB productB1 = factory1.createProductB();
System.out.println(productA1.getName()); // "Product A1"
System.out.println(productB1.getName()); // "Product B1"
// Create a ConcreteFactory2
AbstractFactory factory2 = new ConcreteFactory2();
// Use factory2 to create a ProductA2 and a ProductB2
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB(); System.out.println(productA2.getName()); // "Product A2"
System.out.println(productB2.getName()); // "Product B2"
}
}
Output:
Product A1
Product B1
Product A2
Product B2
The Abstract Factory pattern also has a few drawbacks, including:
- Increased complexity: The Abstract Factory pattern can add complexity to the code, as it requires more classes and interfaces than the Factory Method pattern.
- Increased coupling: The Abstract Factory pattern increases coupling between the client code and the abstract factory, as the client code must use the abstract factory to create objects.
In conclusion, the Abstract Factory pattern provides a way to create objects that belong to a common abstract super-type, without specifying the concrete classes that are being created.