What Is the Factory Design Pattern?

Image of factory

The factory (or factory method) design pattern specializes in delegation and encapsulation. This pattern allows a superclass to defer instantiation to subclasses. This is because the class that contains the primary factory method pattern is abstract.


The original version of the factory method assumes the form of an unimplemented method because it doesn’t know the product that it will create. The factory method might know that it is creating some product, but it doesn’t know the specific characteristics of the product it will create. This knowledge is only available to the respective subclasses. Therefore, the responsibility to implement the factory method and create appropriate objects is solely that of a subclass.


Implementing the Factory Design Pattern in Java

This article utilizes a sample feedback report generation application. This application uses the different types of feedback a company receives (for a new snack) to create specific reports (using the factory method). Therefore, the factory pattern will create specific feedback (or feedback report), using the following primary product class as a base:

 public abstract class Feedback {
    
   private String reviewerName;
   private String reviewMessage;
   private int reviewRatings;
    
   public Feedback(String reviewerName, String reviewMessage, int reviewRatings) {
        this.reviewerName = reviewerName;
        this.reviewMessage = reviewMessage;
        this.reviewRatings = reviewRatings;
  }
    
  public String getReviewerName() {
      return reviewerName;
  }
  public void setReviewerName(String reviewerName) {
      this.reviewerName = reviewerName;
  }
  public String getReviewMessage() {
      return reviewMessage;
  }
  public void setReviewMessage(String reviewMessage) {
      this.reviewMessage = reviewMessage;
  }
  public int getReviewRatings() {
      return reviewRatings;
  }
  public void setReviewRatings(int reviewRatings) {
      this.reviewRatings = reviewRatings;
  }
}

Every feedback will have three mandatory properties, a reviewer name, a review message, and a number rating (from one to five) for the new snack. The different types of feedback the company will receive will come from one of three channels:

Email Feedback Class

 public class EmailFeedback extends Feedback {
    
  private String reviewerEmail;

  public EmailFeedback(String reviewerName, String reviewMessage, int reviewRatings, String reviewerEmail) {
     super(reviewerName, reviewMessage, reviewRatings);
     this.reviewerEmail = reviewerEmail;
  }
  public String getReviewerEmail() {
     return reviewerEmail;
  }
  public void setReviewerEmail(String reviewerEmail) {
     this.reviewerEmail = reviewerEmail;
  }
}

Mail Feedback Class

 public class MailFeedback extends Feedback {
    
   private String returnAddress;
    
   public MailFeedback(String reviewerName, String reviewMessage, int reviewRatings, String returnAddress) {
        super(reviewerName, reviewMessage, reviewRatings);
        this.returnAddress = returnAddress;
     }

   public String getReturnAddress() {
       return returnAddress;
     }

   public void setReturnAddress(String returnAddress) {
       this.returnAddress = returnAddress;
     }
}

Social Media Feedback Class

 public class SocialMediaFeedback extends Feedback {

   private String reviewerHandle;

   public SocialMediaFeedback(String reviewerName, String reviewMessage, int reviewRatings, String reviewerHandle) {
        super(reviewerName, reviewMessage, reviewRatings);
        this.reviewerHandle = reviewerHandle;
     }
    
   public String getReviewerHandle() {
       return reviewerHandle;
     }

   public void setReviewerHandle(String reviewerHandle) {
       this.reviewerHandle = reviewerHandle;
     }
}

You’ll notice that each feedback subclass has a unique property. This means that you will need to create the report for each feedback type using at least one property that is unique to that type.

The Simple Factory

A simple factory is a popular approach to using the factory design pattern. This approach entails grouping all the different feedbacks (or products) in a method (the simple factory) and selecting the appropriate feedback based on a parameter.

 public class FeedbackReportFactory {
    
    public Feedback makeFeedback(String feedbackType) {
         Feedback feedback = null;
          
         if(feedbackType.equals("email")) {
               feedback = new EmailFeedback();
         }else if (feedbackType.equals("mail")) {
               feedback = new MailFeedback();
         }else if (feedbackType.equals("social")) {
               feedback = new SocialMediaFeedback();
         }
     return feedback;
     }
}

However, the simple factory approach is not the factory design pattern, nor it is a design pattern. It is more like a design concept.

The Factory Method

The factory method is the true representation of the design pattern. Using the factory method, the reformed FeedbackReportFactory Java class will now contain the following code:

 public abstract class FeedbackReportFactory {
    public abstract void makeFeedbackReport(Feedback feedback);
}

You can define the structure of the factory design pattern with the following class diagram:

From the diagram above you’ll see that an abstract class (or interface) will contain an abstract version of the factory method. So, the concrete factory classes that extend the abstract class will implement the factory method, using properties that are unique to the product it wants to create. You should also note that any concrete factory class should create one or more products.

The sample application has three related but unique products. Each feedback type has at least one unique property. So, the application will need to have three concrete factories to build each product.

Email Feedback Factory

 public class EmailFeedbackReport extends FeedbackReportFactory{
    
    EmailFeedback feedback;

    @Override
    public void makeFeedbackReport(Feedback feedback) {
          
        this.feedback = (EmailFeedback) feedback;
          
        System.out.println("\nReport For Feedback Via Email" +
                  "\nReviewer Name: " +this.feedback.getReviewerName() +
                  "\nFeedback: " + this.feedback.getReviewMessage() +
                  "\nRatings: " + this.feedback.getReviewRatings() +
                  "\nEmal Address: " + this.feedback.getReviewerEmail());
     }
}

Mail Feedback Factory

 public class MailFeedbackReport extends FeedbackReportFactory {
    MailFeedback feedback;

    @Override
    public void makeFeedbackReport(Feedback feedback) {
         this.feedback = (MailFeedback) feedback;
          
         System.out.println("\nReport For Feedback Via Mail" +
                     "\nReviewer Name: " +this.feedback.getReviewerName() +
                     "\nFeedback: " + this.feedback.getReviewMessage() +
                     "\nRatings: " + this.feedback.getReviewRatings() +
                     "\nMailing Address: " + this.feedback.getReturnAddress());
     }
}

Social Media Feedback Factory

 public class SocialMediaFeedbackReport extends FeedbackReportFactory {
    SocialMediaFeedback feedback;

    @Override
    public void makeFeedbackReport(Feedback feedback) {
        this.feedback = (SocialMediaFeedback) feedback;
                
        System.out.println("\nReport For Feedback Via Social Media" +
                      "\nReviewer Name: " + this.feedback.getReviewerName() +
                      "\nFeedback: " + this.feedback.getReviewMessage() +
                      "\nRatings: " + this.feedback.getReviewRatings() +
                      "\nReviewer Social Media Handle: " + this.feedback.getReviewerHandle());
           }
}

Testing the Sample Application

Now you can use the respective factory methods to make miniature reports on the feedback received from the different channels. You can test the application using JUnit, or you can create a driver class:

 public class Main {

   public static void main(String[] args) {
       Feedback feedback = new EmailFeedback("Nick", "Great product!", 5, "[email protected]");
       Feedback feedback2 = new MailFeedback("john", "The product is good but not something I would buy regularly", 4, "first Street");
       Feedback feedback3 = new SocialMediaFeedback("Jane", "It's not for me", 2, "@janey");
          
       FeedbackReportFactory factory = new EmailFeedbackReport();
       FeedbackReportFactory factory2 = new MailFeedbackReport();
       FeedbackReportFactory factory3 = new SocialMediaFeedbackReport();
          
       factory.makeFeedbackReport(feedback);
       factory2.makeFeedbackReport(feedback2);
       factory3.makeFeedbackReport(feedback3);
   }

The Main class above uses the respective factories to create three reports, producing the following output in the console:

Factory method console output

Advantages of Using the Factory Design Pattern

The factory design pattern promotes design flexibility, where you use interfaces (or abstract classes) to create concrete classes. It also promotes scalability through polymorphism, by allowing new classes to implement the existing interface as the application expands.

When you use the factory design pattern, you’re utilizing two important design principles: Open-closed and Inversion of Control (IoC).

Total
0
Shares
Leave a Reply
Previous Article
A Neanderthal skull next to a human skull.

Human and Neanderthal brains have a surprising 'youthful' quality in common, new research finds

Next Article
woman studying candlestick chart

What Is Crypto Fear and Greed Index, and How Does It Work?

Related Posts