Factory design pattern in Java

Last updated : Jul 30, 2023 12:00 AM

What is the factory design pattern?

In object-oriented programming, the factory design pattern is a creational design pattern that encapsulates the object-creational logic. The factory pattern relies on factory methods to create objects, and the caller is unaware of the classes of resulting objects the factory pattern returns.

Stationery stationery = ProductFactory.getProduct(stationeryName);

The stationery can be a pen, pencil, book, etc.

When to use the factory pattern?

An ideal situation is when you have an interface and several classes that implement the interface (a typical object-oriented implementation). Based on factory method implementation logic, the factory method caller will receive objects of these subclasses. Therefore, the factory pattern is most suitable for creating objects dynamically at run-time.

In practice, let's take stationery as an example. Stationery can consider a product category. Pens, books, paper clips, etc., are sub-categories that belong to stationery. Therefore, stationery is a candidate for our interface, and sub-categories can represent subclasses that implement our interface.

How to implement the factory pattern?

The implementation is a factory for subclasses. That's what it is. The factory pattern returns one of the subclasses based on callers' requirements. Let's look at a code example. We have a parent interface, Stationery, that abstracts the basic behavior of a generic piece of stationery.

interface Stationary{
   public String getProductInfo(){}
}

The Book class implements the Product interface with its properties pages and price. It also overrides parents' getProductInfo with its implementation.

Book class implements StationaryDescription
class Book implements Stationery{
   private int pages;
   private BigDecimal price;
   public Book(int pages, BigDecimal price){
      this.pages = pages ;
      this.price = price;
   }
   public String getProductInfo(){
      return "This book costs: $"+price+" and it has :" +pages + "pages";
   }
}

The Pen class implements the Stationery interface and has its own properties, color, and price. Like the Book class, Pen overrides the getProductInfo() method with its implementation.

Pen class implements StationaryDescription
class Pen implements Stationery{
   private String color;
   public BigDecimal price;
   public Pen(String color, BigDecimal price){
      this.price = price;
      this.color = color;
   }
   public String getProductInfo(){
      return "This pen costs: $"+price+" and it writes in :" +color;
   }
}

The factory class is self-explanatory. The best practice is using an enum class to hold class names instead of hardcoded ones. If you are not new to object-oriented programming, you will notice that the ProductFactory class is the essence of the factory design pattern in this example.

Factory for stationaryDescription
class ProductFactory{
   public static Product getProduct(String product){
      if("Book".equalsIgnoreCase(product)){
         return new Book(500, new BigDecimal("24.95"));
      }
      if("Pen".equalsIgnoreCase(product)){
         return new Pen("Blue", new BigDecimal("0.95"));
      }
      else
         return null;
   }
}

Here is the code to test the implemented concept.

Testing the factoryDescription
public class FactoryPattern{
   public static void main(String args[]){
      Stationary book = ProductFactory.getProduct("Book");
      System.out.println(book.getProductInfo());

      Stationary pen = ProductFactory.getProduct("Pen");
      System.out.println(pen.getProductInfo());
   }
}

Note that we request objects from the factory twice. In both requests, we receive objects of the type Stationery. But the actual sub-class differs based on the argument we passed to the getProduct() method.

Conclusion

The factory design pattern encapsulates object-creational logic from its users by providing factory methods that instantiate objects based on arguments the factory methods receive. The resulting objects are the parent class type, and the implementing class is determined by the argument passed to the factory method. These behaviors make the factory design pattern ideal for creating objects dynamically at run-time.

Lance

By: Lance

Hi, I'm Lance Raney, a dedicated Fullstack Developer based in Oklahoma with over 15 years of exp

Read more...