Last Updated on August 30, 2023 by KnownSense
The Abstract Factory pattern is a powerful design tool that facilitates the creation of families of related objects without specifying their concrete classes. By providing an abstract interface for creating objects, this pattern enables the creation of object hierarchies with consistent structure.
In Factory Method, we implemented furniture business to deliver different types furniture. Now these furnitures can be available in different variants like Modern, Victorian, ArtDeco. We need a method to create furniture pieces that look the same as others in their group. Customers become unhappy if they receive furniture that doesn’t match.
Furthermore, you aim to avoid modifying current code when introducing new products or groups of products into the software. Furniture suppliers frequently update their product offerings, and you’d prefer not to alter the main code each time this occurs.
Benefits
Benefits of the Abstract Factory pattern include:
- Consistency: Ensures that all objects produced by a factory are from the same family and adhere to a common theme or design.
- Flexibility: Allows adding new product variants or families without changing the existing client code.
- Decoupling: Clients are shielded from the specifics of object creation, reducing dependencies and promoting a modular design.
- Maintenance: Eases maintenance as changes in product creation logic are confined to the factory classes, avoiding widespread modifications.
- Scalability: Supports the creation of multiple related objects, making it adaptable to systems with evolving requirements.
- Design Integrity: Maintains a consistent design and structure for related objects, enhancing overall software design quality.
UML for Abstract Factory
Implementation
In this implementation, we will extend furniture business to add variants Modern, Victorian and ArtDeco
Step1: Create a Interface Furniture with method deliver
public interface Furniture {
public void deliver();
}
Step2: Create concrete classes for interface Furniture (Art_DecorChair.java, ModernChair.java, ModernSofa.java..etc..)
public class ModernSofa implements Furniture {
@Override
public void deliver() {
System.out.println("Deliver of Modern Sofa is successful");
}
}
public class ModernTable implements Furniture {
@Override
public void deliver() {
System.out.println("Deliver of Modern Table is successful");
}
}
public class ModernChair implements Furniture {
@Override
public void deliver() {
System.out.println("Deliver of Modern Chair is successful");
}
}
public class Art_DecorChair implements Furniture { @Override public void deliver() { System.out.println("Deliver of Art_Decor Chair is successful"); } }
Step3: Create a Interface AbstractFactoryProducer with method that return Furniture of specific family or variant.
public interface AbstractFactoryProducer {
public Furniture getFur(String name);
}
Step4: Create concrete classes for interface AbstractFactoryProducer
public class ModernFurniture implements AbstractFactoryProducer{
@Override
public Furniture getFur(String name) {
if(name.equalsIgnoreCase("Chair"))
return new ModernChair();
else if(name.equalsIgnoreCase("Sofa"))
return new ModernSofa();
else if(name.equalsIgnoreCase("Table"))
return new ModernTable();
return null;
}
}
public class Art_DecoFurniture implements AbstractFactoryProducer{
@Override
public Furniture getFur(String name) {
if(name.equalsIgnoreCase("Chair"))
return new Art_DecorChair();
else if(name.equalsIgnoreCase("Sofa"))
return new Art_DecorSofa();
else if(name.equalsIgnoreCase("Table"))
return new Art_DecorTable();
return null;
}
}
public class VictorianFurniture implements AbstractFactoryProducer{
@Override
public Furniture getFur(String name) {
if(name.equalsIgnoreCase("Chair"))
return new VictorianChair();
else if(name.equalsIgnoreCase("Sofa"))
return new VictorianSofa();
else if(name.equalsIgnoreCase("Table"))
return new VictorianTable();
return null;
}
}
Step5: Create a class FactoryProducer to get factories by passing an information such as type of furniture
public class FactoryProducer {
public AbstractFactoryProducer getVariant(String type){
if(type.equalsIgnoreCase("Art Deco")){
return new Art_DecoFurniture();
}
else if (type.equalsIgnoreCase("Modern")){
return new ModernFurniture();
}
else if(type.equalsIgnoreCase("Victorian")){
return new VictorianFurniture();
}
return null;
}
}
Step6: In main method, use the FactoryProducer to get AbstractFactory in order to get factories of concrete classes by passing an information
public class DesignAbstractFactory {
public static void main(String args[]){
FactoryProducer factoryProducer = new FactoryProducer();
// customer1 order
AbstractFactoryProducer abstractFactoryProducer= factoryProducer.getVariant("Modern");
abstractFactoryProducer.getFur("Chair").deliver();
abstractFactoryProducer.getFur("Sofa").deliver();
abstractFactoryProducer.getFur("Table").deliver();
System.out.println("====================");
// customer2 order
AbstractFactoryProducer abstractFactoryProducer2= factoryProducer.getVariant("Art Deco");
abstractFactoryProducer2.getFur("Chair").deliver();
abstractFactoryProducer2.getFur("Sofa").deliver();
abstractFactoryProducer2.getFur("Table").deliver();
}
}
OUTPUT:
Deliver of Modern Chair is successful
Deliver of Modern Sofa is successful
Deliver of Modern Table is successful
====================
Deliver of Art_Decor Chair is successful
Deliver of Art_Decor Sofa is successful
Deliver of Art_Decor Table is successful
Conclusion
In conclusion, the Abstract Factory pattern proves its worth by providing a structured approach to creating families of related objects while preserving code flexibility and minimizing modifications. This pattern’s ability to support consistent design themes, accommodate future product additions, and maintain clear object creation interfaces makes it an essential tool for building modular and adaptable software systems.